public static DuplexStreamMessage CreateSubscribeResponse(DuplexCallbackId id, int clientSubscriptionId, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); return(new DuplexStreamMessage(QbservableProtocolMessageKind.DuplexSubscribeResponse, id, clientSubscriptionId, Serialize(id, clientSubscriptionId, protocol))); }
public virtual async void SendOnNext(string name, DuplexCallbackId id, object value) { #if TRACE var sourceId = GetSourceId(id); Log.OnNext(name, value, false, false, sourceId, LogMessages.Sending); #endif try { await Protocol.SendMessageSafeAsync(CreateOnNext(id, value)).ConfigureAwait(false); } catch (SerializationException ex) { SendOnError(name, id, ExceptionDispatchInfo.Capture(ex)); } catch (Exception ex) { if (Protocol.ServiceOptions.SendServerErrorsToClients) { SendOnError(name, id, ExceptionDispatchInfo.Capture(ex)); } else { Fail(ExceptionDispatchInfo.Capture(ex)); } } }
public static DuplexStreamMessage CreateOnCompleted(DuplexCallbackId id, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); return(CreateWithoutValue(QbservableProtocolMessageKind.DuplexOnCompleted, id, protocol)); }
protected void MoveNext(DuplexCallbackId id) { var enumerator = GetEnumerator(id.ClientId); object current; bool result; try { if (enumerator != null && enumerator.MoveNext()) { result = true; current = enumerator.Current; } else { result = false; current = null; } } catch (Exception ex) { SendEnumeratorError(id, ex); return; } SendEnumeratorResponse(id, result, current); }
public Tuple <DuplexCallbackId, IDisposable> RegisterObservableCallbacks(int clientId, Action <object> onNext, Action <Exception> onError, Action onCompleted, Action <int> dispose) { var serverId = Interlocked.Increment(ref lastObservableId); var id = new DuplexCallbackId(clientId, serverId); var actions = Tuple.Create(onNext, onError, onCompleted, dispose); if (!observableCallbacks.TryAdd(id, actions)) { throw new InvalidOperationException(Errors.ProtocolDuplicateDuplexIdForObservable); } return(Tuple.Create( id, Disposable.Create(() => { lock (actions) { int?clientSubscriptionId = null; if (TryGetOrAddSubscriptionOneTime(id, ref clientSubscriptionId)) { Contract.Assume(clientSubscriptionId.HasValue); // Disposable.Create ensures that this code only runs once actions.Item4(clientSubscriptionId.Value); } } }))); }
protected void GetEnumerator(DuplexCallbackId id) { var enumerable = GetEnumerable(id.ClientId); #if TRACE var sourceId = GetSourceId(id); Log.Enumerating(enumerable.Name, false, sourceId, LogMessages.Received); #endif IEnumerator enumerator; try { enumerator = enumerable.GetEnumerator(); } catch (Exception ex) { SendGetEnumeratorError(id, ExceptionDispatchInfo.Capture(ex)); return; } var enumeratorId = RegisterEnumerator(new NamedEnumerator(enumerable.Name, enumerator)); SendGetEnumeratorResponse(id, enumeratorId); }
public static DuplexStreamMessage CreateInvoke(DuplexCallbackId id, object[] arguments, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); return(new DuplexStreamMessage(QbservableProtocolMessageKind.DuplexInvoke, id, arguments, Serialize(id, arguments, protocol))); }
public void SendOnError(string name, DuplexCallbackId id, ExceptionDispatchInfo error) { #if TRACE Contract.Requires(!string.IsNullOrEmpty(name)); #endif Contract.Requires(error != null); }
protected void Subscribe(DuplexCallbackId id) { Func <int, IDisposable> subscribe; if (!obsevableCallbacks.TryGetValue(id.ClientId, out subscribe)) { throw new InvalidOperationException(Errors.ProtocolInvalidDuplexId); } var subscription = new SingleAssignmentDisposable(); var subscriptionId = RegisterSubscription(subscription); try { subscription.Disposable = subscribe(id.ServerId); } catch (Exception ex) { SendOnError(id, ex); return; } SendSubscribeResponse(id, subscriptionId); }
public static DuplexStreamMessage CreateOnNext(DuplexCallbackId id, object value, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); return(new DuplexStreamMessage(QbservableProtocolMessageKind.DuplexOnNext, id, value, Serialize(id, value, protocol))); }
private DuplexStreamMessage(QbservableProtocolMessageKind kind, DuplexCallbackId id, ExceptionDispatchInfo error, byte[] data) : base(kind, data, data.Length) { Contract.Requires(error != null); Id = id; Error = error; }
public static DuplexStreamMessage CreateOnError(DuplexCallbackId id, ExceptionDispatchInfo error, StreamQbservableProtocol protocol) { Contract.Requires(error != null); Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); return(new DuplexStreamMessage(QbservableProtocolMessageKind.DuplexOnError, id, error, Serialize(id, error.SourceException, protocol))); }
public static DuplexStreamMessage CreateEnumeratorResponse(DuplexCallbackId id, bool result, object current, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <DuplexStreamMessage>() != null); var value = Tuple.Create(result, current); return(new DuplexStreamMessage(QbservableProtocolMessageKind.DuplexEnumeratorResponse, id, value, Serialize(id, value, protocol))); }
private DuplexStreamMessage(QbservableProtocolMessageKind kind, DuplexCallbackId id, object value, byte[] data, long length) : base(kind, data, length) { Contract.Requires(length >= 0); Contract.Requires(length == 0 || data != null); Contract.Requires(length == 0 || data.Length >= length); Id = id; Value = value; }
private Tuple <Action <object>, Action <Exception> > GetEnumeratorCallbacks(DuplexCallbackId id) { Tuple <Action <object>, Action <Exception> > actions; if (!enumeratorCallbacks.TryGetValue(id, out actions)) { throw new InvalidOperationException(Errors.ProtocolInvalidDuplexIdForEnumerator); } return(actions); }
protected virtual async void SendError(DuplexCallbackId id, ExceptionDispatchInfo error) { try { await Protocol.SendMessageSafeAsync(CreateErrorResponse(id, error)).ConfigureAwait(false); } catch (Exception ex) { Fail(ExceptionDispatchInfo.Capture(ex)); } }
protected virtual async void SendEnumeratorResponse(DuplexCallbackId id, bool result, object current) { try { await Protocol.SendMessageSafeAsync(CreateEnumeratorResponse(id, result, current)).ConfigureAwait(false); } catch (Exception ex) { Fail(ExceptionDispatchInfo.Capture(ex)); } }
protected virtual async void SendGetEnumeratorResponse(DuplexCallbackId id, int clientEnumeratorId) { try { await Protocol.SendMessageSafeAsync(CreateGetEnumeratorResponse(id, clientEnumeratorId)).ConfigureAwait(false); } catch (Exception ex) { Fail(ExceptionDispatchInfo.Capture(ex)); } }
public DuplexCallbackId RegisterEnumeratorCallback(int clientId, Action <object> callback, Action <Exception> onError) { var serverId = Interlocked.Increment(ref lastEnumeratorId); var id = new DuplexCallbackId(clientId, serverId); if (!enumeratorCallbacks.TryAdd(id, Tuple.Create(callback, onError))) { throw new InvalidOperationException(Errors.ProtocolDuplicateDuplexIdForEnumerator); } return(id); }
protected void ResetEnumerator(DuplexCallbackId id) { var enumerator = GetEnumerator(id.ClientId); try { enumerator.Reset(); } catch (Exception ex) { SendEnumeratorError(id, ex); } }
protected virtual async void SendEnumeratorError(DuplexCallbackId id, ExceptionDispatchInfo error) { Contract.Requires(error != null); try { await Protocol.SendMessageSafeAsync(CreateEnumeratorError(id, error)).ConfigureAwait(false); } catch (Exception ex) { Fail(ExceptionDispatchInfo.Capture(ex)); } }
private static byte[] Serialize(DuplexCallbackId id, object value, QbservableProtocol protocol) { var idData = BitConverter.GetBytes(id); long serializedDataLength; var serializedData = protocol.Serialize(value, out serializedDataLength); var data = new byte[idData.Length + serializedDataLength]; Array.Copy(idData, data, idData.Length); Array.Copy(serializedData, 0, data, idData.Length, serializedDataLength); return(data); }
private void TryInvokeObservableCallback( DuplexCallbackId id, Action <Tuple <Action <object>, Action <Exception>, Action, Action <int> > > action) { Tuple <Action <object>, Action <Exception>, Action, Action <int> > callbacks; if (observableCallbacks.TryGetValue(id, out callbacks)) { action(callbacks); } /* It's acceptable for the callbacks to be missing due to a race condition between the * client sending notifications and the server disposing of the subscription, which causes * the callbacks to be removed. */ }
private static byte[] Serialize(DuplexCallbackId id, object value, StreamQbservableProtocol protocol) { Contract.Requires(protocol != null); Contract.Ensures(Contract.Result <byte[]>() != null); var idData = BitConverter.GetBytes(id); long serializedDataLength; var serializedData = protocol.Serialize(value, out serializedDataLength); var data = new byte[idData.Length + serializedDataLength]; Array.Copy(idData, data, idData.Length); Array.Copy(serializedData, 0, data, idData.Length, serializedDataLength); return(data); }
protected void DisposeEnumerator(DuplexCallbackId id) { var enumerator = GetEnumerator(id.ClientId); #if TRACE var sourceId = GetSourceId(id); Log.Enumerated(enumerator.Name, false, sourceId, LogMessages.Received); #endif var disposable = enumerator.Decorated as IDisposable; if (disposable != null) { disposable.Dispose(); } }
public virtual async void SendOnCompleted(string name, DuplexCallbackId id) { #if TRACE var sourceId = GetSourceId(id); Log.OnCompleted(name, false, false, sourceId, LogMessages.Sending); #endif try { await Protocol.SendMessageSafeAsync(CreateOnCompleted(id)).ConfigureAwait(false); } catch (Exception ex) { Fail(ExceptionDispatchInfo.Capture(ex)); } }
private bool TryGetOrAddSubscriptionOneTime(DuplexCallbackId id, ref int?clientSubscriptionId) { int?s; if (subscriptions.TryGetValue(id, out s)) { subscriptions.Remove(id); clientSubscriptionId = s; return(true); } else { subscriptions.Add(id, clientSubscriptionId); } return(false); }
protected void MoveNext(DuplexCallbackId id) { var enumerator = GetEnumerator(id.ClientId); #if TRACE var sourceId = GetSourceId(id); if (enumerator != null) { Log.MoveNext(enumerator.Name, false, sourceId, LogMessages.Received); } #endif object current; bool result; try { if (enumerator != null && enumerator.MoveNext()) { result = true; current = enumerator.Current; } else { result = false; current = null; } } catch (Exception ex) { SendEnumeratorError(id, ExceptionDispatchInfo.Capture(ex)); return; } #if TRACE if (result) { Log.Current(enumerator.Name, current, false, sourceId, LogMessages.Sending); } #endif SendEnumeratorResponse(id, result, current); }
protected void GetEnumerator(DuplexCallbackId id) { var enumerable = GetEnumerable(id.ClientId); IEnumerator enumerator; try { enumerator = enumerable(); } catch (Exception ex) { SendGetEnumeratorError(id, ex); return; } var enumeratorId = RegisterEnumerator(enumerator); SendGetEnumeratorResponse(id, enumeratorId); }
protected void Invoke(DuplexCallbackId id, object[] arguments) { Contract.Requires(arguments != null); IInvokeDuplexCallback callback; if (!invokeCallbacks.TryGetValue(id.ClientId, out callback)) { throw new InvalidOperationException(Errors.ProtocolInvalidDuplexId); } #if TRACE var sourceId = GetSourceId(id); Log.Invoking(callback.Name, arguments, false, sourceId, LogMessages.Received); #endif object result; try { result = callback.Invoke(arguments); } catch (Exception ex) { SendError(id, ExceptionDispatchInfo.Capture(ex)); return; } var duplex = result as DuplexCallback; if (duplex != null) { duplex.SetClientProtocol(Protocol); } #if TRACE Log.Invoked(callback.Name, arguments, result, false, sourceId, LogMessages.Sending); #endif SendResponse(id, result); }