private async Task <IArgumentParserResult> ParseCommandAsync(CommandContext context, ICommand command, string rawArgs)
        {
            var provider = context.CommandServices;

            IArgumentParser argumentParser;
            var             argumentParserType = command.GetArgumentParserType();

            if (argumentParserType.HasContent())
            {
                argumentParser = provider.GetService(argumentParserType) as IArgumentParser;

                if (argumentParser.HasNoContent())
                {
                    argumentParser = ActivatorUtilities.CreateInstance(provider, argumentParserType) as IArgumentParser;

                    MiddlewareUtils.RegisterForDispose(argumentParser, context);
                }
            }
            else
            {
                argumentParser = provider.GetRequiredService <IArgumentParser>();
            }


            return(await argumentParser.ParseAsync(context, command, rawArgs));
        }
        private async Task ParseCommandFromMatchesAsync(CommandContext context, CommandDelegate next)
        {
            context.Features.Set <IArgumentParserFeature>(new ArgumentParserFeature());

            var matchesFeature        = context.Features.Get <ICommandMatchesFeature>();
            var argumentParserFeature = context.Features.Get <IArgumentParserFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var bestMatches = new List <ICommandMatch>();

            var fails = new Dictionary <ICommand, IResult>();

            foreach (var match in matchesFeature.CommandMatches)
            {
                var result = await ParseCommandAsync(context, match.Command, match.RemainingInput);

                if (result.Success)
                {
                    bestMatches.Add(match);
                    argumentParserFeature.CommandArgs.Add(match, result.Args.Values.ToArray());
                }
                else
                {
                    fails.Add(match.Command, result);
                }
            }


            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for command parsing.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            var config = context.CommandServices.GetRequiredService <IOptions <MariCommandsOptions> >().Value;

            if (!config.ContinueMultiMatchAfterParser)
            {
                bestMatches = bestMatches
                              .OrderByDescending(a => a.Command.Priority)
                              .Take(1)
                              .ToList();

                var bestMatch = bestMatches.FirstOrDefault();

                context.Command = bestMatch.Command;
                context.Alias   = bestMatch.Alias;
                context.Args    = argumentParserFeature.CommandArgs[bestMatch].ToList();
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }
        private ITypeParser GetTypeParser(CommandContext context, IParameter param)
        {
            var typeParserType = param.TypeParserType;

            if (typeParserType.HasContent())
            {
                var typeParser = context.CommandServices.GetService(typeParserType) as ITypeParser;

                if (typeParser.HasNoContent())
                {
                    typeParser = ActivatorUtilities.CreateInstance(context.CommandServices, typeParserType) as ITypeParser;

                    MiddlewareUtils.RegisterForDispose(typeParser, context);
                }

                return(typeParser);
            }

            var typeParserProvider = context.CommandServices.GetRequiredService <ITypeParserProvider>();

            var parameterType = param.IsParams
                ? param.ParameterInfo.ParameterType.GetElementType()
                : param.ParameterInfo.ParameterType;

            return(typeParserProvider.GetTypeParser(parameterType));
        }
Example #4
0
        private object GetModule(CommandContext context, ICommand command)
        {
            var module = command.Module.Invoker.CreateInstance(context.CommandServices);

            MiddlewareUtils.RegisterForDispose(module, context);

            return(module);
        }
        /// <summary>
        /// Add a middleware type to the command request pipeline.
        /// </summary>
        /// <param name="app">The current command aplication builder.</param>
        /// <param name="middlewareArgs">Additional ctor args for this middleware.</param>
        /// <returns>The current command aplication builder.</returns>
        public static ICommandApplicationBuilder UseMiddleware <TMiddleware>(this ICommandApplicationBuilder app, params object[] middlewareArgs)
            where TMiddleware : ICommandMiddleware
        {
            app.Use((next) =>
            {
                var types = middlewareArgs
                            ?.Select(a => a.GetType())
                            ?.ToArray() ?? new Type[0];

                var instanceFactory = ActivatorUtilities.CreateFactory(typeof(TMiddleware), types ?? Type.EmptyTypes);

                return(async context =>
                {
                    var instance = instanceFactory(context.CommandServices, middlewareArgs);

                    await(instance as ICommandMiddleware).InvokeAsync(context, next);

                    await MiddlewareUtils.SwitchDisposeAsync(instance);
                });
            });

            return(app);
        }
        public async Task InvokeAsync(CommandContext context, CommandDelegate next)
        {
            context.NotNull(nameof(context));

            if (context.Result.HasContent())
            {
                await next(context);

                return;
            }

            var isUniqueCommand =
                context.Command.HasContent() &&
                context.Args != null;

            if (isUniqueCommand)
            {
                var result = await ExecutePreconditionsForContextAsync(context);

                if (result.Success)
                {
                    await next(context);
                }
                else
                {
                    context.Result = result;
                }

                return;
            }

            var matchesFeature = context.Features.Get <ICommandMatchesFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var argumentParserFeature = context.Features.Get <IArgumentParserFeature>();

            if (argumentParserFeature.HasNoContent() || argumentParserFeature.CommandArgs.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches parsed param values from feature: {nameof(IArgumentParserFeature)}.");
            }

            var matches    = matchesFeature.CommandMatches;
            var parsedArgs = argumentParserFeature.CommandArgs;

            var fails       = new Dictionary <ICommand, IResult>();
            var bestMatches = new List <ICommandMatch>();

            foreach (var match in matches)
            {
                var command = match.Command;
                var args    = parsedArgs[match];

                var result = await ExecutePreconditionsAsync(command, args, context);

                if (result.Success)
                {
                    bestMatches.Add(match);
                }
                else
                {
                    fails.Add(command, result);
                }
            }

            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for input count.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }
Example #7
0
        public async Task InvokeAsync(CommandContext context, CommandDelegate next)
        {
            context.NotNull(nameof(context));

            if (context.Result.HasContent() || context.Args != null)
            {
                await next(context);

                return;
            }

            var verifyCommandInputCount =
                context.Command.HasContent() &&
                !string.IsNullOrWhiteSpace(context.RawArgs);

            if (verifyCommandInputCount)
            {
                context.Features.Set <ICommandMatchesFeature>(new CommandMatchesFeature
                {
                    CommandMatches = new List <ICommandMatch>
                    {
                        new CommandMatch(context.Command, null, null, context.RawArgs)
                    }
                });
            }

            var matchesFeature = context.Features.Get <ICommandMatchesFeature>();

            if (matchesFeature.HasNoContent() || matchesFeature.CommandMatches.HasNoContent())
            {
                throw new InvalidOperationException($"Can't get command matches from feature: {nameof(ICommandMatchesFeature)}.");
            }

            var multiMatches = new List <ICommandMatch>();

            if (matchesFeature.CommandMatches.Count > 1)
            {
                multiMatches = matchesFeature.CommandMatches
                               .Where(a => a.Command.Module.GetMatchHandling(_config) == MultiMatchHandling.Best)
                               .ToList();
            }
            else
            {
                multiMatches = matchesFeature.CommandMatches.ToList();
            }

            if (multiMatches.HasNoContent())
            {
                _logger.LogInformation($"This input has more than one match but none of then has {MultiMatchHandling.Best} as configuration.");
                context.Result = MultiMatchErrorResult.FromMatches(matchesFeature.CommandMatches);
                return;
            }

            matchesFeature.CommandMatches = multiMatches;

            var bestMatches = new List <ICommandMatch>();

            var fails = new Dictionary <ICommand, IResult>();

            foreach (var match in matchesFeature.CommandMatches)
            {
                var inputCount = string.IsNullOrWhiteSpace(match.RemainingInput)
                    ? 0
                    : match.RemainingInput.Split(_config.Separator).Count();

                var command = match.Command;

                if (command.Parameters.Count > inputCount)
                {
                    var hasAnyOptional = command.Parameters.Any(a => IsOptional(a));

                    if (!hasAnyOptional)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }

                    var optionalsCount = command.Parameters.Count(a => IsOptional(a));

                    var missingCount = command.Parameters.Count - inputCount;

                    if (optionalsCount < missingCount)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }
                }
                else if (command.Parameters.Count < inputCount)
                {
                    var ignoreExtraArgs = command.GetIgnoreExtraArgs(_config);

                    if (!ignoreExtraArgs)
                    {
                        fails.Add(command, BadArgCountResult.FromCommand(command));
                        continue;
                    }
                }

                bestMatches.Add(match);
            }

            if (bestMatches.HasNoContent())
            {
                _logger.LogInformation("All matched commands returned fail for input count.");
                context.Result = MiddlewareUtils.GetErrorResult(fails);

                return;
            }

            matchesFeature.CommandMatches = bestMatches;

            await next(context);
        }