public Future <RelayMessage> Send(RelayMessage relayMessage) { var publisher = new FuturePublisher <RelayMessage>(); var stopwatch = Stopwatch.StartNew(); try { _transport.BeginSendMessage(relayMessage, relayMessage.IsTwoWayMessage, asyncResult => { try { _transport.EndSendMessage(asyncResult); publisher.SetRelayMessageResult(relayMessage); UpdateStatistics(!publisher.Future.HasError, stopwatch.ElapsedTicks); } catch (Exception ex) { UpdateStatistics(false, stopwatch.ElapsedTicks); publisher.SetError(ex); } }, null); } catch (Exception ex) { UpdateStatistics(false, stopwatch.ElapsedTicks); publisher.SetError(ex); } return(publisher.Future); }
/// <summary> /// A convenience method to create an error Future for when a type is not present in the Data Relay configuration. /// </summary> /// <typeparam name="T">The type to create an error future for.</typeparam> /// <returns>The error future.</returns> public static Future <T> InvalidTypeFuture <T>() { var futureObject = new FuturePublisher <T>(); futureObject.SetError(new InvalidOperationException(String.Format("The type \"{0}\" is not configured for use with Data Relay.", typeof(T).FullName))); return(futureObject.Future); }
private Future <RelayMessage> NoMatchingServer(TypeSetting typeSetting, RelayMessage relayMessage) { var noMatchingServerMessage = String.Format("No Data Relay server is in the server mapping for group/id {0}/{1}", typeSetting.GroupName, relayMessage.Id); _log.ErrorFormat(noMatchingServerMessage); var serverNotFoundFuture = new FuturePublisher <RelayMessage>(); serverNotFoundFuture.SetError(new ApplicationException(noMatchingServerMessage)); // TODO: use a better exception type return(serverNotFoundFuture.Future); }
private static void TryNextServer(FuturePublisher <RelayMessage> publisher, RelayMessage relayMessage, Exception lastException, IEnumerator <RelayEndPoint> servers) { if (servers.MoveNext()) { if (!publisher.Future.IsCanceled) { var serverResponse = servers.Current.RelayMessageSender.Send(relayMessage); serverResponse.OnSuccess(() => publisher.SetResult(serverResponse.Result)); serverResponse.OnError(ex => TryNextServer(publisher, relayMessage, ex, servers)); } } else { publisher.SetError(new ApplicationException("Send Message failed for all available matching servers.", lastException)); } }
/// <summary> /// Sends the relay message. /// </summary> /// <param name="typeSetting">The type setting.</param> /// <param name="relayMessage">The relay message.</param> /// <returns>A future with the possibly resuling RelayMessage. Result will be null if it is a miss.</returns> public Future <RelayMessage> SendRelayMessage(TypeSetting typeSetting, RelayMessage relayMessage) { var endPoints = _servers.GetEndPoints(typeSetting.GroupName, relayMessage.Id); var endPointEnumerator = endPoints.GetEnumerator(); if (!endPointEnumerator.MoveNext()) { return(NoMatchingServer(typeSetting, relayMessage)); } endPointEnumerator.Reset(); var publisher = new FuturePublisher <RelayMessage>(); TryNextServer(publisher, relayMessage, null, endPointEnumerator); return(publisher.Future); }
/// <summary> /// Completes a FuturePublisher{RelayMessage} with the results of a Future{Stream}. /// </summary> /// <param name="publisher">The publisher.</param> /// <param name="futureStream">The future stream.</param> /// <returns></returns> public static FuturePublisher <RelayMessage> CompleteWith(this FuturePublisher <RelayMessage> publisher, Future <Stream> futureStream) { futureStream.OnComplete(() => { if (futureStream.HasError) { publisher.SetError(futureStream.Error); } else if (futureStream.IsCanceled) { publisher.SetError(new ApplicationException("Transport operation was cancelled.")); } else { try { using (var reply = futureStream.Result) { if (reply == null || reply.Length == 0) { publisher.SetResult(default(RelayMessage)); } else { var replyMessage = Serializer.Deserialize <RelayMessage>(reply, SerializerFlags.Default); SetRelayMessageResult(publisher, replyMessage); } } } catch (Exception ex) { publisher.SetError(ex); } } }); return(publisher); }
/// <summary> /// Completes a FuturePublisher{RelayMessage} with a RelayMessage. /// </summary> /// <param name="publisher">The publisher.</param> /// <param name="relayMessage">The relay message.</param> /// <returns></returns> public static FuturePublisher <RelayMessage> SetRelayMessageResult(this FuturePublisher <RelayMessage> publisher, RelayMessage relayMessage) { if (relayMessage.MessageType == MessageType.Get) { publisher.SetResult(relayMessage); } else { switch (relayMessage.ResultOutcome) { case RelayOutcome.Success: publisher.SetResult(relayMessage); break; case RelayOutcome.Timeout: publisher.SetError(new TimeoutException(String.Format("{0} timed out.", relayMessage.MessageType))); break; case null: if (!relayMessage.IsTwoWayMessage) { publisher.SetResult(relayMessage); } else { publisher.SetError(new Exception(String.Format("{0} failed with {1}.", relayMessage.MessageType, relayMessage.ResultOutcome))); } break; default: publisher.SetError(new Exception(String.Format("{0} failed with {1}.", relayMessage.MessageType, relayMessage.ResultOutcome))); break; } } return(publisher); }