async void buttonSendMessage_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                using (var connection = new SocketConnection("127.0.0.1", 4525, Scheduler.Immediate))
                {
                    var publisher = connection.AsPublisher();

                    await publisher.PublishMessage("alert1", textBoxMessage.Text);
                    //await publisher.PublishMessage("alert2", textBoxMessage.Text);
                }

                using (var connection = new SocketConnection("127.0.0.1", 4525, Scheduler.Immediate))
                {
                    var cacheClient = connection.AsCacheClient();

                    //await cacheClient.SetValue("alert1", textBoxMessage.Text);
                    var result  = await cacheClient.GetValues(new string[]{"alert1", "alert3"});
                    await cacheClient.Del("alert1");
                    var result2 = await cacheClient.GetValues(new string[] { "alert1", "alert3" });
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        public RedisCacheClient(SocketConnection socketConnection)
        {
            if (socketConnection == null)
                throw new ArgumentNullException("socketConnection");

            this.socketConnection = socketConnection;
        }
        public async Task CanPublishAndReceiveMultipleMessagesOnChannel()
        {
            var expected = "CanPublishAndReceiveOnChannel";

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                using (var publisherConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
                {
                    var subscriber = socketConnection.AsSubscriber();
                    var publisher = publisherConnection.AsPublisher();
                    var matchedReplies = 0;
                    var tcs = new TaskCompletionSource<bool>();
                    var expectedMessagesCount = 512;

                    var messagesChannel = await subscriber.Subscribe("channel1");
                    messagesChannel.Subscribe(message =>
                    {
                        if (string.Compare(message.Content, expected, StringComparison.InvariantCultureIgnoreCase) == 0)
                            matchedReplies += 1;

                        if (matchedReplies == expectedMessagesCount)
                            tcs.SetResult(true);
                    });

                    foreach (var once in Enumerable.Repeat(Unit.Default, expectedMessagesCount))
                    {
                        var result = await publisher.PublishMessage("channel1", expected);
                    }

                    await Task.WhenAny(Task.Delay(1000), tcs.Task);
                    Assert.AreEqual(expectedMessagesCount, matchedReplies);
                }
            }
        }
        public async Task CanSetKeyAndGetValue()
        {
            var expected = "CanSetKeyAndGetValue";

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                var cacheClient = socketConnection.AsCacheClient();
                await cacheClient.SetValue("test1", expected);
                var cacheValue = await cacheClient.GetValue("test1");

                Assert.AreEqual(expected, cacheValue);
            }
        }
        public async Task CanSetMultipleKeysAndGetValues()
        {
            var expected = "CanSetMultipleKeysAndGetValues";
            var map = new Dictionary<string, string>();
            map.Add("test2", expected);
            map.Add("test3", expected);

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                var cacheClient = socketConnection.AsCacheClient();
                await cacheClient.SetValues(map);
                var cacheValues = await cacheClient.GetValues(map.Keys.ToArray());

                Assert.AreEqual(expected, cacheValues.Take(1).First());
                Assert.AreEqual(expected, cacheValues.Skip(1).Take(1).First());
            }
        }
        async void Subscribe()
        {
            var connection = new SocketConnection("127.0.0.1", 4525, Scheduler.Immediate);
            var currentSyncronizationContext = SynchronizationContext.Current;
            var subscriber = connection.AsSubscriber();

            try
            {
                var channelMessagesReceived = 0;
                var channelsSubscription = await subscriber.Subscribe("alert1");
                channelsSubscription
                    .Buffer(TimeSpan.FromSeconds(1))
                    .ObserveOn(currentSyncronizationContext)
                    .Subscribe(messages =>
                    {
                        channelMessagesReceived += messages.Count;
                        channelMessages.Text = channelMessagesReceived.ToString();
                        //listBoxAlerts.Items.Add(new ListBoxItem { Content = message.ChannelName + ":" + message.Content });
                    },
                    ex =>
                    {
                        MessageBox.Show(ex.ToString());
                    });

                var patternChannelMessagesReceived = 0;
                var channelsPatternSubscription = await subscriber.PSubscribe("alert*");
                channelsPatternSubscription
                    .Buffer(TimeSpan.FromSeconds(1))
                    .ObserveOn(currentSyncronizationContext)
                    .Subscribe(messages =>
                    {
                        patternChannelMessagesReceived += messages.Count;
                        channelPatternMessages.Text = patternChannelMessagesReceived.ToString();
                        //listBoxAlerts.Items.Add(new ListBoxItem { Content = message.Pattern + ":" + message.Content });
                    },
                    ex =>
                    {
                        MessageBox.Show(ex.ToString());
                    });
            }
            catch (AggregateException ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
        public async Task CanSetKeysAndThenDeleteAll()
        {
            var expected = "CanSetKeysAndThenDeleteAll";

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                var cacheClient = socketConnection.AsCacheClient();
                var map = new Dictionary<string, string>();
                map.Add("test5", expected);
                map.Add("test6", expected);

                await cacheClient.SetValues(map);
                await cacheClient.Del(map.Keys.ToArray());

                var cacheValues = await cacheClient.GetValues(map.Keys.ToArray());

                Assert.IsTrue(cacheValues.All(x => x == null));
            }
        }
        public async Task CanPublishAndReceiveOnChannel()
        {
            var expected = "CanPublishAndReceiveOnChannel";

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                using (var publisherConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
                {
                    var subscriber = socketConnection.AsSubscriber();
                    var publisher = publisherConnection.AsPublisher();

                    var messagesChannel = await subscriber.Subscribe("channel1");
                    var replaySubject = new ReplaySubject<string>();
                    messagesChannel.Take(1).Select(x => x.Content).Subscribe(replaySubject);

                    await publisher.PublishMessage("channel1", expected);
                    var result = await replaySubject.FirstAsync();

                    Assert.AreEqual(expected, result); 
                }
            }
        }
        public RedisSubscriber(SocketConnection socketConnection)
        {
            if (socketConnection == null)
                throw new ArgumentNullException("socketConnection");

            this.socketConnection = socketConnection;
            this.upstreamChannelMessages = new Subject<RedisChannelMessage>();
            this.upstreamChannelPatternMessages = new Subject<RedisChannelPatternMessage>();
            this.disposables = new CompositeDisposable();
            this.remainder = string.Empty;

            Func<bool> tryParseRemainder = () =>
            {
                var parseChannelPatternMessage = RedisChannelPatternMessage.RedisChannelPatternMessageParser.TryParse(remainder);
                if (parseChannelPatternMessage.WasSuccessful)
                {
                    var position = parseChannelPatternMessage.Remainder.Position;
                    remainder = parseChannelPatternMessage.Remainder.Source.Substring(position);
                    upstreamChannelPatternMessages.OnNext(parseChannelPatternMessage.Value);
                    return true;
                }

                var parseSubscriptionMessage = RedisParsersModule.SubscriptionMessageParser.TryParse(remainder);
                if (parseSubscriptionMessage.WasSuccessful)
                {
                    var position = parseSubscriptionMessage.Remainder.Position;
                    remainder = parseSubscriptionMessage.Remainder.Source.Substring(position);
                    return true;
                }

                var parseChannelMessage = RedisChannelMessage.RedisChannelMessageParser.TryParse(remainder);
                if (parseChannelMessage.WasSuccessful)
                {
                    var position = parseChannelMessage.Remainder.Position;
                    remainder = parseChannelMessage.Remainder.Source.Substring(position);
                    upstreamChannelMessages.OnNext(parseChannelMessage.Value);
                    return true;
                }

                return false;
            };

            disposables.Add(upstreamChannelMessages);
            disposables.Add(upstreamChannelPatternMessages);
            disposables.Add(
                socketConnection
                    .GetConnection()
                    .Select(connection =>
                        connection.ReceiveMessage())
                    .Merge(1)
                    .DoWhile(() => !socketConnection.IsDisposed)
                .SubscribeOn(socketConnection.Scheduler)
                .Subscribe(message =>
                {
                    if (message.StartsWith("-", StringComparison.InvariantCultureIgnoreCase))
                    {
                        var error = new ParseException(remainder);
                        upstreamChannelMessages.OnError(error);
                        upstreamChannelPatternMessages.OnError(error);
                    }

                    remainder += message;
                    bool previousMessageWasParsed = false;
                    do
                    {
                        previousMessageWasParsed = tryParseRemainder();
                    }
                    while (previousMessageWasParsed);
                 }, 
                 ex => 
                 {
                     upstreamChannelMessages.OnError(ex);
                     upstreamChannelPatternMessages.OnError(ex);
                 },
                 () =>
                 {
                     upstreamChannelMessages.OnCompleted();
                     upstreamChannelPatternMessages.OnCompleted();
                 }));
        }
        public async Task CanSetKeyAndGetText()
        {
            var expected = Enumerable.Repeat("CanSetKeyAndGetText", 1024)
                .Aggregate(
                    new StringBuilder(), 
                    (builder, value) => builder.Append(value),
                    builder => builder.ToString());

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                var cacheClient = socketConnection.AsCacheClient();
                await cacheClient.SetValue("test7", expected);
                var cacheValue = await cacheClient.GetValue("test7");

                Assert.AreEqual(expected, cacheValue);
            }
        }
        public async Task ChannelsObservablesDontThrowExceptionWhenSocketConnectionIsDisposed()
        {
            var subscriptionCompleted = new TaskCompletionSource<bool>();

            using (var socketConnection = new SocketConnection(TestsSetup.Host, TestsSetup.Port, Scheduler.Immediate))
            {
                var subscriber = socketConnection.AsSubscriber();

                var channelPatternMessages = await subscriber.PSubscribe("channel*");

                channelPatternMessages.Subscribe(
                    _ => { }, 
                    ex => {
                        subscriptionCompleted.SetException(ex);
                    },
                    () => { subscriptionCompleted.SetResult(true); });
            }

            try
            {
                var completed = await subscriptionCompleted.Task;
                Assert.IsTrue(completed);
            }
            catch (AggregateException ex)
            {
                if (ex.InnerException is RedisException)
                {
                    throw new Exception(((RedisException)ex.InnerException).SocketError.ToString());
                }

                throw ex.InnerException;
            }
        }