예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="Connection"/> class.
        /// </summary>
        /// <param name="url">The url to connect to.</param>
        /// <param name="queryString">The query string data to pass to the server.</param>
        public Connection(string url, string queryString)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            if (url.Contains("?"))
            {
                throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Resources.Error_UrlCantContainQueryStringDirectly), "url");
            }

            if (!url.EndsWith("/", StringComparison.Ordinal))
            {
                url += "/";
            }

            Url            = url;
            QueryString    = queryString;
            _groups        = new HashSet <string>();
            Items          = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);
            State          = ConnectionState.Disconnected;
            _disconnectCts = new SafeCancellationTokenSource();
            _disconnectTimeoutOperation = DisposableAction.Empty;
        }
예제 #2
0
        protected virtual void InitializePersistentState()
        {
            _hostShutdownToken = _context.Environment.GetShutdownToken();

            _requestLifeTime = new HttpRequestLifeTime(this, WriteQueue, Trace, ConnectionId);

            // Create the TCS that completes when the task returned by PersistentConnection.OnConnected does.
            _connectTcs = new TaskCompletionSource <object>();

            // Create a token that represents the end of this connection's life
            _connectionEndTokenSource = new SafeCancellationTokenSource();
            _connectionEndToken       = _connectionEndTokenSource.Token;

            // Handle the shutdown token's callback so we can end our token if it trips
            _hostRegistration = _hostShutdownToken.SafeRegister(state =>
            {
                ((SafeCancellationTokenSource)state).Cancel();
            },
                                                                _connectionEndTokenSource);

            // When the connection ends release the request
            _connectionEndRegistration = CancellationToken.SafeRegister(state =>
            {
                ((HttpRequestLifeTime)state).Complete();
            },
                                                                        _requestLifeTime);
        }
예제 #3
0
        public IReadOnlyList <Activity> GetActivities(IObservable <Activity> observable)
        {
            var cancellationToken = new SafeCancellationTokenSource();
            var activityObserver  = new GitHubActivityObserver(_logger, cancellationToken, _lastObservation);

            observable.Subscribe(activityObserver, cancellationToken.Token);

            cancellationToken.Token.WaitHandle.WaitOne(TimeSpan.FromSeconds(5));

            var observedActivities = activityObserver.ObservedActivities;

            if (observedActivities.Count > 0)
            {
                foreach (var observedActivity in observedActivities)
                {
                    if (observedActivity.CreatedAt > _lastObservation)
                    {
                        _lastObservation = observedActivity.CreatedAt;
                    }
                }

                _lastObservation = _lastObservation.AddMilliseconds(1);
            }

            return(activityObserver.ObservedActivities);
        }
예제 #4
0
        public Task <IClientResponse> ProcessRequest(string url, Action <IClientRequest> prepareRequest, Dictionary <string, string> postData, bool disableWrites)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            if (prepareRequest == null)
            {
                throw new ArgumentNullException("prepareRequest");
            }

            var uri = new Uri(url);
            PersistentConnection connection;

            if (!_shutDownToken.IsCancellationRequested && TryGetConnection(uri.LocalPath, out connection))
            {
                var tcs = new TaskCompletionSource <IClientResponse>();
                var clientTokenSource = new SafeCancellationTokenSource();
                var request           = new Request(uri, clientTokenSource.Cancel, postData, User);
                prepareRequest(request);

                Response response = null;
                response = new Response(clientTokenSource.Token, () => tcs.TrySetResult(response))
                {
                    DisableWrites = disableWrites
                };
                var hostContext = new HostContext(request, response);

                hostContext.Items[HostConstants.ShutdownToken] = _shutDownTokenSource.Token;

                connection.Initialize(DependencyResolver, hostContext);

                connection.ProcessRequestAsync(hostContext).ContinueWith(task =>
                {
                    if (task.IsFaulted)
                    {
                        tcs.TrySetException(task.Exception);
                    }
                    else if (task.IsCanceled)
                    {
                        tcs.TrySetCanceled();
                    }
                    else
                    {
                        tcs.TrySetResult(response);
                    }

                    response.Close();
                    clientTokenSource.Dispose();
                });

                return(tcs.Task);
            }

            return(TaskAsyncHelper.FromError <IClientResponse>(new InvalidOperationException("Not a valid end point")));
        }
예제 #5
0
 public GitHubActivityObserver(
     ILogger logger,
     SafeCancellationTokenSource cancellationToken,
     DateTimeOffset lastObservation)
 {
     _logger             = logger;
     _cancellationToken  = cancellationToken;
     _lastObservation    = lastObservation;
     _observedActivities = new List <Activity>();
 }
예제 #6
0
        public async Task <bool> OpenAsync(object args = null)
        {
            if (_isOpen)
            {
                return(await RunFunctionIfOpenAsyncA(delegate { IsEnabledAllowed = true; }).ConfigureAwait(false));
            }

            lock (_isOpenSemaphoreLocker)
            {
                if (!SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
                {
                    _isOpenSemaphore = new SemaphoreSlimSafeRelease(1, 1);
                }
            }
            try
            {
                await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);

                if (!_isOpen)
                {
                    lock (_ctsLocker)
                    {
                        _cts?.Dispose();
                        _cts       = new SafeCancellationTokenSource();
                        _cancToken = _cts.Token;
                    }

                    await OpenMayOverrideAsync(args).ConfigureAwait(false);

                    IsOpen           = true;
                    IsEnabledAllowed = true;

                    await RegisterBackEventHandlersAsync().ConfigureAwait(false);

                    //Logger.Add_TPL($"OpenableObservablePage.OpenAsync: {GetType().Name} is now open", Logger.AppEventsLogFilename, Logger.Severity.Info, false);
                    return(true);
                }
            }
            catch (Exception ex)
            {
                if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
                {
                    await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
                }
            }
            finally
            {
                SemaphoreSlimSafeRelease.TryRelease(_isOpenSemaphore);
            }

            return(false);
        }
예제 #7
0
        public async Task <bool> CloseAsync(object args = null)
        {
            if (!_isOpen)
            {
                return(await RunFunctionIfOpenAsyncA(delegate { IsEnabledAllowed = false; }).ConfigureAwait(false));
            }

            lock (_ctsLocker)
            {
                _cts?.CancelSafe(true);
            }

            try
            {
                await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);

                if (_isOpen)
                {
                    lock (_ctsLocker)
                    {
                        _cts?.Dispose();
                        _cts       = null;
                        _cancToken = new CancellationToken(true); // CancellationToken is not nullable and not disposable
                    }

                    await UnregisterBackEventHandlersAsync();

                    IsEnabledAllowed = false;
                    IsOpen           = false;

                    await CloseMayOverrideAsync(args).ConfigureAwait(false);

                    return(true);
                }
            }
            catch (Exception ex)
            {
                if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
                {
                    await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
                }
            }
            finally
            {
                lock (_isOpenSemaphoreLocker)
                {
                    SemaphoreSlimSafeRelease.TryDispose(_isOpenSemaphore);
                    _isOpenSemaphore = null;
                }
            }
            return(false);
        }
예제 #8
0
        public ClientStream(INetworkObserver networkObserver, SafeCancellationTokenSource callCancelledTokenSource)
        {
            _cancelToken = _cancelTokenSource.Token;
            _callCancelledTokenSource = callCancelledTokenSource;

            networkObserver.OnCancel = () =>
            {
                _cancelTokenSource.Cancel(useNewThread: false);
                _callCancelledTokenSource.Cancel();
            };

            networkObserver.OnClose = OnClose;
            networkObserver.OnWrite = OnWrite;
        }
예제 #9
0
        public async Task <bool> OpenAsync(object args = null)
        {
            if (!_isOpen)
            {
                lock (_isOpenSemaphoreLocker)
                {
                    if (!SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
                    {
                        _isOpenSemaphore = new SemaphoreSlimSafeRelease(1, 1);
                    }
                }
                try
                {
                    await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);

                    if (!_isOpen)
                    {
                        lock (_ctsLocker)
                        {
                            _cts?.Dispose();
                            _cts       = new SafeCancellationTokenSource();
                            _cancToken = _cts.Token;
                        }

                        await OpenMayOverrideAsync(args).ConfigureAwait(false);

                        IsOpen           = true;
                        IsEnabledAllowed = true;
                        return(true);
                    }
                }
                catch (Exception ex)
                {
                    if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
                    {
                        await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
                    }
                }
                finally
                {
                    SemaphoreSlimSafeRelease.TryRelease(_isOpenSemaphore);
                }
            }
            if (_isOpen)
            {
                await SetIsEnabledAsync(true).ConfigureAwait(false);
            }
            return(false);
        }
예제 #10
0
		//protected Func<Task> _runAsSoonAsOpen = null;
		#endregion properties


		#region open close
		public async Task<bool> OpenAsync(object args = null)
		{
			if (_isOpen) return false;

			if (!SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore)) _isOpenSemaphore = new SemaphoreSlimSafeRelease(1, 1);
			try
			{
				await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);
				if (!_isOpen)
				{
					lock (_ctsLocker)
					{
						_cts?.Dispose();
						_cts = new SafeCancellationTokenSource();
						_cancToken = _cts.Token;
					}

					await OpenMayOverrideAsync(args).ConfigureAwait(false);

					IsOpen = true;

					//try
					//{
					//	var runAsSoonAsOpen = _runAsSoonAsOpen;
					//	if (runAsSoonAsOpen != null)
					//	{
					//		Task asSoonAsOpen = Task.Run(runAsSoonAsOpen, CancToken);
					//	}
					//}
					//catch { }
					//finally { _runAsSoonAsOpen = null; }

					return true;
				}
			}
			catch (Exception ex)
			{
				if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
					await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
			}
			finally
			{
				SemaphoreSlimSafeRelease.TryRelease(_isOpenSemaphore);
			}
			return false;
		}
예제 #11
0
        protected void InitializePersistentState()
        {
            _hostShutdownToken = _context.HostShutdownToken();

            Completed = new TaskCompletionSource <object>();

            // Create a token that represents the end of this connection's life
            _connectionEndTokenSource = new SafeCancellationTokenSource();
            _connectionEndToken       = _connectionEndTokenSource.Token;

            // Handle the shutdown token's callback so we can end our token if it trips
            _hostRegistration = _hostShutdownToken.SafeRegister(state =>
            {
                state.Cancel();
            },
                                                                _connectionEndTokenSource);
        }
예제 #12
0
        /// <summary>
        /// Stops the <see cref="Connection"/> without sending an abort message to the server.
        /// </summary>
        public void Disconnect()
        {
            lock (_stateLock)
            {
                // Do nothing if the connection is offline
                if (State != ConnectionState.Disconnected)
                {
                    _disconnectTimeoutOperation.Dispose();
                    _disconnectCts.Cancel();
                    _disconnectCts.Dispose();
                    _disconnectCts = new SafeCancellationTokenSource();

                    State = ConnectionState.Disconnected;

                    // TODO: Do we want to trigger Closed if we are connecting?
                    if (Closed != null)
                    {
                        Closed();
                    }
                }
            }
        }
예제 #13
0
        protected virtual void InitializePersistentState()
        {
            _hostShutdownToken = _context.HostShutdownToken();

            _requestLifeTime = new HttpRequestLifeTime(WriteQueue, Trace, ConnectionId);

            // Create a token that represents the end of this connection's life
            _connectionEndTokenSource = new SafeCancellationTokenSource();
            _connectionEndToken       = _connectionEndTokenSource.Token;

            // Handle the shutdown token's callback so we can end our token if it trips
            _hostRegistration = _hostShutdownToken.SafeRegister(state =>
            {
                ((SafeCancellationTokenSource)state).Cancel();
            },
                                                                _connectionEndTokenSource);

            // When the connection ends release the request
            _connectionEndRegistration = CancellationToken.SafeRegister(state =>
            {
                ((HttpRequestLifeTime)state).Complete();
            },
                                                                        _requestLifeTime);
        }
예제 #14
0
 public ResponseStream()
 {
     _currentStream           = new MemoryStream();
     _cancellationTokenSource = new SafeCancellationTokenSource();
     _cancellationToken       = _cancellationTokenSource.Token;
 }
예제 #15
0
		public async Task<bool> CloseAsync()
		{
			if (!_isOpen) return false;

			lock (_ctsLocker)
			{
				_cts?.CancelSafe(true);
			}

			try
			{
				await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);
				if (_isOpen)
				{
					lock (_ctsLocker)
					{
						_cts?.Dispose();
						_cts = null;
						_cancToken = new CancellationToken(true); // CancellationToken is not nullable and not disposable
					}

					IsOpen = false;
					await CloseMayOverrideAsync().ConfigureAwait(false);

					return true;
				}
			}
			catch (Exception ex)
			{
				if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
					await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
			}
			finally
			{
				SemaphoreSlimSafeRelease.TryDispose(_isOpenSemaphore);
				_isOpenSemaphore = null;
			}
			return false;
		}
		public async Task<bool> OpenAsync(object args = null)
		{
			if (!_isOpen)
			{
				if (!SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore)) _isOpenSemaphore = new SemaphoreSlimSafeRelease(1, 1);
				try
				{
					await _isOpenSemaphore.WaitAsync().ConfigureAwait(false);
					if (!_isOpen)
					{
						lock (_ctsLocker)
						{
							_cts?.Dispose();
							_cts = new SafeCancellationTokenSource();
							_cancToken = _cts.Token;
						}

						await OpenMayOverrideAsync(args).ConfigureAwait(false);

						IsOpen = true;
						IsEnabledAllowed = true;
						return true;
					}
				}
				catch (Exception ex)
				{
					if (SemaphoreSlimSafeRelease.IsAlive(_isOpenSemaphore))
						await Logger.AddAsync(GetType().Name + ex.ToString(), Logger.ForegroundLogFilename);
				}
				finally
				{
					SemaphoreSlimSafeRelease.TryRelease(_isOpenSemaphore);
				}
			}
			if (_isOpen) await SetIsEnabledAsync(true).ConfigureAwait(false);
			return false;
		}
예제 #17
0
        private Task <IClientResponse> ProcessRequest(string httpMethod, string url, Action <IClientRequest> prepareRequest, IDictionary <string, string> postData, bool disableWrites = false)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            if (prepareRequest == null)
            {
                throw new ArgumentNullException("prepareRequest");
            }

            if (_appFunc == null)
            {
                throw new InvalidOperationException();
            }

            if (_shutDownToken.IsCancellationRequested)
            {
                return(TaskAsyncHelper.FromError <IClientResponse>(new InvalidOperationException("Service unavailable")));
            }

            var tcs = new TaskCompletionSource <IClientResponse>();
            var clientTokenSource = new SafeCancellationTokenSource();

            var env = new Dictionary <string, object>();

            // Server specific setup
            env[OwinConstants.Version] = "1.0";

            // Request specific setup
            var uri = new Uri(url);

            env[OwinConstants.RequestProtocol]    = "HTTP/1.1";
            env[OwinConstants.CallCancelled]      = clientTokenSource.Token;
            env[OwinConstants.RequestMethod]      = httpMethod;
            env[OwinConstants.RequestPathBase]    = String.Empty;
            env[OwinConstants.RequestPath]        = uri.LocalPath;
            env[OwinConstants.RequestQueryString] = uri.Query.Length > 0 ? uri.Query.Substring(1) : String.Empty;
            env[OwinConstants.RequestScheme]      = uri.Scheme;
            env[OwinConstants.RequestBody]        = GetRequestBody(postData);
            var headers = new Dictionary <string, string[]>();

            env[OwinConstants.RequestHeaders] = headers;

            headers.SetHeader("X-Server", "MemoryHost");
            headers.SetHeader("X-Server-Name", InstanceName);

            if (httpMethod == "POST")
            {
                headers.SetHeader("Content-Type", "application/x-www-form-urlencoded");
            }

            // Run the client function to initialize the request
            prepareRequest(new Request(env, clientTokenSource.Cancel));

            var networkObservable = new NetworkObservable(disableWrites);
            var clientStream      = new ClientStream(networkObservable);
            var serverStream      = new ServerStream(networkObservable);

            var response = new Response(clientStream);

            // Trigger the tcs on flush. This mimicks the client side
            networkObservable.OnFlush = () => tcs.TrySetResult(response);

            // Cancel the network observable on cancellation of the token
            clientTokenSource.Token.Register(networkObservable.Cancel);

            env[OwinConstants.ResponseBody]    = serverStream;
            env[OwinConstants.ResponseHeaders] = new Dictionary <string, string[]>();

            _appFunc(env).ContinueWith(task =>
            {
                object statusCode;
                if (env.TryGetValue(OwinConstants.ResponseStatusCode, out statusCode) &&
                    (int)statusCode == 403)
                {
                    tcs.TrySetException(new InvalidOperationException("Forbidden"));
                }
                else if (task.IsFaulted)
                {
                    tcs.TrySetException(task.Exception.InnerExceptions);
                }
                else if (task.IsCanceled)
                {
                    tcs.TrySetCanceled();
                }
                else
                {
                    tcs.TrySetResult(response);
                }

                // Close the server stream when the request has ended
                serverStream.Close();
                clientTokenSource.Dispose();
            });

            return(tcs.Task);
        }