示例#1
0
        public static NmdcUserCommandCommand Parse(string message)
        {
            if (string.IsNullOrWhiteSpace(message))
            {
                return(null);
            }

            var match = ParseRegex.Match(message);

            if (match == null || !match.Success)
            {
                return(null);
            }

            var groups = match.Groups;

            var commandType = (NmdcUserCommandType)byte.Parse(groups[TypeGroupName].Value);
            var context     = (NmdcUserCommandContextType)byte.Parse(groups[ContextGroupName].Value);

            var titleGroup = groups[TitleGroupName];
            var title      = titleGroup.Success
                ? titleGroup.Value
                : string.Empty;

            UserCommandsGenerator commandsGenerator = null;
            var lines         = Enumerable.Empty <string>();
            var commandsGroup = groups[CommandsGroupName];

            if (commandsGroup.Success)
            {
                var gluedMessages = commandsGroup.Value;

                var lineMatch = LineVariableParseRegex.Match(gluedMessages);
                if (lineMatch.Success)
                {
                    lines = lineMatch.Captures.Cast <Capture>().Select(capture => capture.Value);
                }

                var commandsMessages = UnescapeArgument(gluedMessages).Split(new[] { StopChar }, StringSplitOptions.RemoveEmptyEntries);
                commandsGenerator = (nickReplacement, myNickReplacement, lineReplacements) =>
                {
                    var replacements = (lineReplacements ?? new Dictionary <string, string>())
                                       .ToDictionary(line => GetLineVariable(line.Key), line => line.Value);
                    replacements.Add(NickVariable, nickReplacement);
                    replacements.Add(MyNickVariable, myNickReplacement);

                    var regex = new Regex($"({string.Join("|", replacements.Keys.Select(Regex.Escape))})");

                    return((commandsMessages ?? Enumerable.Empty <string>())
                           .Select(m => NmdcCommandParser.Parse(regex.Replace(m, mm => replacements[mm.Value]))));
                };
            }

            return(new NmdcUserCommandCommand(commandType, context, title, lines, commandsGenerator));
        }
示例#2
0
        /// <summary>
        /// Asynchronously receives a sequence of commands and monitors cancellation requests.
        /// </summary>
        /// <param name="cancellationToken">The token to monitor for cancellation requests.</param>
        /// <returns>A task that represents the asynchronous receive operation. The value of
        /// the TResult parameter contains collection of received commands.</returns>
        /// <exception cref="InvalidOperationException">
        ///     <para>Attempt to receive data via dead connection.</para>
        ///     <para>-or-</para>
        ///     <para>Data cannot be received via this connection.</para>
        ///     <para>-or-</para>
        ///     <para>Underlying network stream is currently in use by a previous receive operation.</para>
        /// </exception>
        /// <exception cref="ObjectDisposedException">The connection has been disposed.</exception>
        /// <exception cref="OperationCanceledException">The token has had cancellation requested.</exception>
        public async Task <IEnumerable <NmdcCommand> > ReceiveAsync(CancellationToken cancellationToken)
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(nameof(NmdcHubConnection), "The connection has been disposed.");
            }

            // [0] Check the connection state.

            if (!IsConnected)
            {
                throw new InvalidOperationException("Attempt to receive data via dead connection.");
            }

            if (_networkStream?.CanRead != true)
            {
                throw new InvalidOperationException("Data cannot be received via this connection.");
            }

            // [1] Receive bytes via connection until the command stop byte (|) is encountered.

            cancellationToken.ThrowIfCancellationRequested();

            byte[] commandsBytes = null;

            using (var memoryStream = new MemoryStream())
            {
                if (_receivedBytesRemainder != null && _receivedBytesRemainder.Length > 0)
                {
                    await memoryStream.WriteAsync(_receivedBytesRemainder, 0, _receivedBytesRemainder.Length, cancellationToken);
                }

                while (true)
                {
                    cancellationToken.ThrowIfCancellationRequested();

                    var receivedBytesCount = await _networkStream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length, cancellationToken);

                    if (receivedBytesCount <= 0)
                    {
                        continue;
                    }

                    await memoryStream.WriteAsync(_receiveBuffer, 0, receivedBytesCount, cancellationToken);

                    if (Array.IndexOf(_receiveBuffer, NmdcCommand.StopByte, 0, receivedBytesCount) >= 0)
                    {
                        break;
                    }
                }

                commandsBytes = memoryStream.ToArray();
            }

            // [2] Parse commands presented in the received bytes.

            cancellationToken.ThrowIfCancellationRequested();

            var result = new List <NmdcCommand>();
            var offset = 0;

            while (offset < commandsBytes.Length)
            {
                cancellationToken.ThrowIfCancellationRequested();

                var commandStopBytePosition = Array.IndexOf(commandsBytes, NmdcCommand.StopByte, offset);
                if (commandStopBytePosition < 0)
                {
                    break;
                }

                var message = Encoding.GetString(commandsBytes, offset, commandStopBytePosition - offset);
                var command = NmdcCommandParser.Parse(message);

                result.Add(command);
                OnCommandReceived(message, command);

                offset = commandStopBytePosition + 1;
            }

            // [3] Save the bytes remained after parsing since they must be used as start of a command on next receive operation.

            cancellationToken.ThrowIfCancellationRequested();

            _receivedBytesRemainder = null;
            var receivedDataTailLength = commandsBytes.Length - offset;

            if (receivedDataTailLength > 0)
            {
                _receivedBytesRemainder = new byte[receivedDataTailLength];
                Buffer.BlockCopy(commandsBytes, offset, _receivedBytesRemainder, 0, receivedDataTailLength);
            }

            //

            return(result);
        }