protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result) { switch (result.Type) { case ResultType.MultiBulk: var arr = result.GetItems(); long i64; if (arr.Length == 2 && arr[1].Type == ResultType.MultiBulk && arr[0].TryGetInt64(out i64)) { var keysResult = new ScanResult(i64, arr[1].GetItemsAsKeys()); SetResult(message, keysResult); return(true); } break; } return(false); }
// internally, this is very similar to RawResult, except it is designed to be usable // outside of the IO-processing pipeline: the buffers are standalone, etc internal static RedisResult TryCreate(PhysicalConnection connection, RawResult result) { try { switch (result.Type) { case ResultType.Integer: case ResultType.SimpleString: case ResultType.BulkString: return(new SingleRedisResult(result.AsRedisValue())); case ResultType.MultiBulk: var items = result.GetItems(); var arr = new RedisResult[items.Length]; for (int i = 0; i < arr.Length; i++) { var next = TryCreate(connection, items[i]); if (next == null) { return(null); // means we didn't understand } arr[i] = next; } return(new ArrayRedisResult(arr)); case ResultType.Error: return(new ErrorRedisResult(result.GetString())); default: return(null); } } catch (Exception ex) { connection?.OnInternalError(ex); return(null); // will be logged as a protocol fail by the processor } }
void MatchResult(RawResult result) { // check to see if it could be an out-of-band pubsub message if (connectionType == ConnectionType.Subscription && result.Type == ResultType.MultiBulk) { // out of band message does not match to a queued message var items = result.GetItems(); if (items.Length >= 3 && items[0].IsEqual(message)) { // special-case the configuration change broadcasts (we don't keep that in the usual pub/sub registry) var configChanged = Multiplexer.ConfigurationChangedChannel; if (configChanged != null && items[1].IsEqual(configChanged)) { EndPoint blame = null; try { if (!items[2].IsEqual(RedisLiterals.ByteWildcard)) { blame = Format.TryParseEndPoint(items[2].GetString()); } } catch { /* no biggie */ } Multiplexer.Trace("Configuration changed: " + Format.ToString(blame), physicalName); Multiplexer.ReconfigureIfNeeded(blame, true, "broadcast"); } // invoke the handlers var channel = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal); Multiplexer.Trace("MESSAGE: " + channel, physicalName); if (!channel.IsNull) { Multiplexer.OnMessage(channel, channel, items[2].AsRedisValue()); } return; // AND STOP PROCESSING! } else if (items.Length >= 4 && items[0].IsEqual(pmessage)) { var channel = items[2].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Literal); Multiplexer.Trace("PMESSAGE: " + channel, physicalName); if (!channel.IsNull) { var sub = items[1].AsRedisChannel(ChannelPrefix, RedisChannel.PatternMode.Pattern); Multiplexer.OnMessage(sub, channel, items[3].AsRedisValue()); } return; // AND STOP PROCESSING! } // if it didn't look like "[p]message", then we still need to process the pending queue } Multiplexer.Trace("Matching result...", physicalName); Message msg; lock (outstanding) { Multiplexer.Trace(outstanding.Count == 0, "Nothing to respond to!", physicalName); msg = outstanding.Dequeue(); } Multiplexer.Trace("Response to: " + msg.ToString(), physicalName); if (msg.ComputeResult(this, result)) { Bridge.CompleteSyncOrAsync(msg); } }
protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result) { var tran = message as TransactionMessage; if (tran != null) { var bridge = connection.Bridge; var wrapped = tran.InnerOperations; switch (result.Type) { case ResultType.SimpleString: if (tran.IsAborted && result.IsEqual(RedisLiterals.BytesOK)) { connection.Multiplexer.Trace("Acknowledging UNWATCH (aborted electively)"); SetResult(message, false); return(true); } //EXEC returned with a NULL if (!tran.IsAborted && result.IsNull) { connection.Multiplexer.Trace("Server aborted due to failed EXEC"); //cancel the commands in the transaction and mark them as complete with the completion manager foreach (var op in wrapped) { op.Wrapped.Cancel(); bridge.CompleteSyncOrAsync(op.Wrapped); } SetResult(message, false); return(true); } break; case ResultType.MultiBulk: if (!tran.IsAborted) { var arr = result.GetItems(); if (arr == null) { connection.Multiplexer.Trace("Server aborted due to failed WATCH"); foreach (var op in wrapped) { op.Wrapped.Cancel(); bridge.CompleteSyncOrAsync(op.Wrapped); } SetResult(message, false); return(true); } else if (wrapped.Length == arr.Length) { connection.Multiplexer.Trace("Server committed; processing nested replies"); for (int i = 0; i < arr.Length; i++) { if (wrapped[i].Wrapped.ComputeResult(connection, arr[i])) { bridge.CompleteSyncOrAsync(wrapped[i].Wrapped); } } SetResult(message, true); return(true); } } break; } // even if we didn't fully understand the result, we still need to do something with // the pending tasks foreach (var op in wrapped) { op.Wrapped.Fail(ConnectionFailureType.ProtocolFailure, null); bridge.CompleteSyncOrAsync(op.Wrapped); } } return(false); }