예제 #1
0
        /// <summary>
        /// Registers a scanner that scans received strings.
        /// If a string matches the given pattern, the callback is invoked.
        /// </summary>
        /// <param name="pattern"></param>
        /// <param name="callback"></param>
        /// <returns></returns>
        public CommandRegistry AddScanner(RegexString pattern, ScannerDelegate callback)
        {
            ThrowIfDisposed();

            _queue.AddScanner(pattern, callback);
            return(this);
        }
예제 #2
0
        private void PipeThreadCallback(string[] inputs, InputResultDelegate callback, IContextObject ctx)
        {
            object output = null;

            for (int i = 0; i < inputs.Length; i++)
            {
                string          input = $"{inputs[i]}".Trim();
                CommandMetadata metadata;
                lock (_lock)
                {
                    //Lock the metadata collection, and grab the first metadata that has a matching executor
                    List <CommandMetadata> metadatas = _metadata.Where(m => m.GetFirstOrDefaultExecutorData(input) != null).ToList();
                    metadata = metadatas.FirstOrDefault();
                }

                if (metadata == null)
                {
                    //No command matches, so ignore this entire piped input
                    callback.Invoke(InputResult.Unhandled, null);
                    break;
                }

                CommandExecutorData exeData = metadata.GetFirstOrDefaultExecutorData(input);

                RegexString trigger = exeData.ExecutorAttribute.CommandMatcher;
                input = trigger.RemoveMatchedString(input);
                object[] arguments = null;
                if (output != null)
                {
                    //If there's output from a previous command, append it to the arguments for this command
                    arguments = new[] { output };
                }

                AbstractParser parser;

                if (i == inputs.Length - 1)
                {
                    //We only want the final parsing to invoke the parser callback
                    parser = _registry.GetParser(_registry, input, arguments, metadata, exeData, ctx, callback);
                }
                else
                {
                    parser = _registry.GetParser(_registry, input, arguments, metadata, exeData, ctx, null);
                }

                //Threads are joined for synchronous behaviour. Running each command concurrently (and thus potentially out of order) will not work here.
                Thread thread = parser.GetThread();
                thread.Start();
                thread.Join();

                //Set output so that it's appended to the end of the next input
                output = parser.Output;
            }
        }
예제 #3
0
 internal ScannerData(RegexString pattern, ScannerDelegate callback)
 {
     Pattern  = pattern;
     Callback = callback;
 }
예제 #4
0
        private void ParserThreadCallback()
        {
            while (!_tokenSource.Token.IsCancellationRequested)
            {
                //Check if the MRE has been set
                if (!_mre.WaitOne(100))
                {
                    continue;
                }

                if (!_queue.TryDequeue(out QueueData data))
                {
                    _mre.Reset();
                    continue;
                }

                //The vertical bar is a pipe character. inputA | inputB = run command B with the output of command A
                string[] inputs = data.Input.Split('|');

                if (inputs.Length > 1)
                {
                    //If we have a piped command, send it off to a new thread to be handled,
                    //As each command needs to be handled in order
                    Thread pipeThread = new Thread(() => PipeThreadCallback(inputs, data.Callback, data.Context));
                    pipeThread.Start();
                    _mre.Set();
                    continue;
                }

                string input = data.Input; //We don't lower the data because case sensitivity is an option for command matching

                CommandMetadata metadata;
                lock (_lock)
                {
                    //Lock the metadata collection, and grab the first metadata that has a matching executor
                    List <CommandMetadata> metadatas = _metadata.Where(m => m.GetFirstOrDefaultExecutorData(input) != null).ToList();
                    metadata = metadatas.FirstOrDefault();
                }

                if (metadata == null)
                {
                    data.Callback?.Invoke(InputResult.Unhandled, null);

                    //No command matches, so ignore this input
                    _mre.Set();
                    continue;
                }

                CommandExecutorData exeData = metadata.GetFirstOrDefaultExecutorData(input);

                RegexString trigger = exeData.ExecutorAttribute.CommandMatcher;
                input = trigger.RemoveMatchedString(input).TrimStart();

                AbstractParser parser = _registry.GetParser(_registry, input, null, metadata, exeData, data.Context, data.Callback);

                try
                {
                    parser.Start();
                }
                finally
                {
                    //Our job is done, so prepare for the next input
                    _mre.Set();
                }
            }

            _mre.Dispose();
        }
예제 #5
0
        /// <summary>
        /// Adds a new scanner
        /// </summary>
        /// <param name="pattern">The scanner's pattern</param>
        /// <param name="callback">The scanner's callback</param>
        public void AddScanner(RegexString pattern, ScannerDelegate callback)
        {
            ThrowIfDisposed();

            _scanners.Add(new ScannerData(pattern, callback));
        }