private void OnLocalUserSignIn(ConnectionOptions options, UserDto user)
 {
     // TODO: Create a separate property for this
     if (options.UpdateDateLastAccessed)
     {
         if (LocalUserSignIn != null)
         {
             LocalUserSignIn(this, new GenericEventArgs<UserDto>(user));
         }
     }
 }
        private async Task OnAuthenticated(IApiClient apiClient,
            AuthenticationResult result,
            ConnectionOptions options,
            bool saveCredentials)
        {
            var server = ((ApiClient)apiClient).ServerInfo;

            var credentials = await _credentialProvider.GetServerCredentials().ConfigureAwait(false);

            if (options.UpdateDateLastAccessed)
            {
                server.DateLastAccessed = DateTime.UtcNow;
            }

            if (saveCredentials)
            {
                server.UserId = result.User.Id;
                server.AccessToken = result.AccessToken;
            }
            else
            {
                server.UserId = null;
                server.AccessToken = null;
            }

            credentials.AddOrUpdateServer(server);
            SaveUserInfoIntoCredentials(server, result.User);
            await _credentialProvider.SaveServerCredentials(credentials).ConfigureAwait(false);

            AfterConnected(apiClient, options);

            OnLocalUserSignIn(options, result.User);
        }
        private async Task ValidateAuthentication(ServerInfo server, ConnectionMode connectionMode, ConnectionOptions options, CancellationToken cancellationToken)
        {
            _logger.Debug("Validating saved authentication");

            var url = server.GetAddress(connectionMode);

            var headers = new HttpHeaders();
            headers.SetAccessToken(server.AccessToken);

            var request = new HttpRequest
            {
                CancellationToken = cancellationToken,
                Method = "GET",
                RequestHeaders = headers,
                Url = url + "/emby/system/info?format=json"
            };

            try
            {
                using (var stream = await _httpClient.SendAsync(request).ConfigureAwait(false))
                {
                    var systemInfo = JsonSerializer.DeserializeFromStream<SystemInfo>(stream);

                    server.ImportInfo(systemInfo);
                }

                if (!string.IsNullOrEmpty(server.UserId))
                {
                    request.Url = url + "/mediabrowser/users/" + server.UserId + "?format=json";

                    using (var stream = await _httpClient.SendAsync(request).ConfigureAwait(false))
                    {
                        var localUser = JsonSerializer.DeserializeFromStream<UserDto>(stream);

                        SaveUserInfoIntoCredentials(server, localUser);

                        OnLocalUserSignIn(options, localUser);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                throw;
            }
            catch (Exception ex)
            {
                // Already logged at a lower level

                server.UserId = null;
                server.AccessToken = null;
            }
        }
        private async Task OnSuccessfulConnection(ServerInfo server,
            ConnectionOptions options,
            PublicSystemInfo systemInfo,
            ConnectionResult result,
            ConnectionMode connectionMode,
            CancellationToken cancellationToken)
        {
            server.ImportInfo(systemInfo);

            var credentials = await _credentialProvider.GetServerCredentials().ConfigureAwait(false);

            if (!string.IsNullOrWhiteSpace(credentials.ConnectAccessToken))
            {
                await EnsureConnectUser(credentials, cancellationToken).ConfigureAwait(false);

                if (!string.IsNullOrWhiteSpace(server.ExchangeToken))
                {
                    await AddAuthenticationInfoFromConnect(server, connectionMode, credentials, cancellationToken).ConfigureAwait(false);
                }
            }

            if (!string.IsNullOrWhiteSpace(server.AccessToken))
            {
                await ValidateAuthentication(server, connectionMode, options, cancellationToken).ConfigureAwait(false);
            }

            credentials.AddOrUpdateServer(server);

            if (options.UpdateDateLastAccessed)
            {
                server.DateLastAccessed = DateTime.UtcNow;
            }
            server.LastConnectionMode = connectionMode;

            await _credentialProvider.SaveServerCredentials(credentials).ConfigureAwait(false);

            result.ApiClient = GetOrAddApiClient(server, connectionMode);
            result.State = string.IsNullOrEmpty(server.AccessToken) ?
                ConnectionState.ServerSignIn :
                ConnectionState.SignedIn;

            ((ApiClient)result.ApiClient).EnableAutomaticNetworking(server, connectionMode, _networkConnectivity);

            if (result.State == ConnectionState.SignedIn)
            {
                AfterConnected(result.ApiClient, options);
            }

            CurrentApiClient = result.ApiClient;

            result.Servers.Add(server);

            if (Connected != null)
            {
                Connected(this, new GenericEventArgs<ConnectionResult>(result));
            }
        }
        public async Task<ConnectionResult> Connect(ServerInfo server, ConnectionOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            var result = new ConnectionResult
            {
                State = ConnectionState.Unavailable
            };

            PublicSystemInfo systemInfo = null;
            var connectionMode = ConnectionMode.Manual;

            var tests = new[] { ConnectionMode.Manual, ConnectionMode.Local, ConnectionMode.Remote }.ToList();

            // If we've connected to the server before, try to optimize by starting with the last used connection mode
            if (server.LastConnectionMode.HasValue)
            {
                tests.Remove(server.LastConnectionMode.Value);
                tests.Insert(0, server.LastConnectionMode.Value);
            }

            var isLocalNetworkAvailable = _networkConnectivity.GetNetworkStatus().GetIsAnyLocalNetworkAvailable();

            // Kick off wake on lan on a separate thread (if applicable)
            var sendWakeOnLan = server.WakeOnLanInfos.Count > 0 && isLocalNetworkAvailable;

            var wakeOnLanTask = sendWakeOnLan ?
                Task.Run(() => WakeServer(server, cancellationToken), cancellationToken) :
                Task.FromResult(true);

            var wakeOnLanSendTime = DateTime.Now;

            foreach (var mode in tests)
            {
                _logger.Debug("Attempting to connect to server {0}. ConnectionMode: {1}", server.Name, mode.ToString());

                if (mode == ConnectionMode.Local)
                {
                    // Try connect locally if there's a local address,
                    // and we're either on localhost or the device has a local connection
                    if (!string.IsNullOrEmpty(server.LocalAddress) && isLocalNetworkAvailable)
                    {
                        // Try to connect to the local address
                        systemInfo = await TryConnect(server.LocalAddress, 8000, cancellationToken).ConfigureAwait(false);
                    }
                }
                else if (mode == ConnectionMode.Manual)
                {
                    // Try manual address if there is one, but only if it's different from the local/remote addresses
                    if (!string.IsNullOrEmpty(server.ManualAddress)
                        && !string.Equals(server.ManualAddress, server.LocalAddress, StringComparison.OrdinalIgnoreCase)
                        && !string.Equals(server.ManualAddress, server.RemoteAddress, StringComparison.OrdinalIgnoreCase))
                    {
                        // Try to connect to the local address
                        systemInfo = await TryConnect(server.ManualAddress, 15000, cancellationToken).ConfigureAwait(false);
                    }
                }
                else if (mode == ConnectionMode.Remote)
                {
                    if (!string.IsNullOrEmpty(server.RemoteAddress))
                    {
                        systemInfo = await TryConnect(server.RemoteAddress, 15000, cancellationToken).ConfigureAwait(false);
                    }
                }

                if (systemInfo != null)
                {
                    connectionMode = mode;
                    break;
                }
            }

            if (systemInfo == null && !string.IsNullOrEmpty(server.LocalAddress) && isLocalNetworkAvailable && sendWakeOnLan)
            {
                await wakeOnLanTask.ConfigureAwait(false);

                // After wake on lan finishes, make sure at least 10 seconds have elapsed since the time it was first sent out
                var waitTime = TimeSpan.FromSeconds(10).TotalMilliseconds -
                               (DateTime.Now - wakeOnLanSendTime).TotalMilliseconds;

                if (waitTime > 0)
                {
                    await Task.Delay(Convert.ToInt32(waitTime, CultureInfo.InvariantCulture), cancellationToken).ConfigureAwait(false);
                }

                systemInfo = await TryConnect(server.LocalAddress, 15000, cancellationToken).ConfigureAwait(false);
            }

            if (systemInfo != null)
            {
                await OnSuccessfulConnection(server, options, systemInfo, result, connectionMode, cancellationToken)
                        .ConfigureAwait(false);
            }

            result.ConnectUser = ConnectUser;
            return result;
        }
        private async void AfterConnected(IApiClient apiClient, ConnectionOptions options)
        {
            if (options.ReportCapabilities)
            {
                try
                {
                    await apiClient.ReportCapabilities(ClientCapabilities).ConfigureAwait(false);
                }
                catch (Exception ex)
                {
                    _logger.ErrorException("Error reporting capabilities", ex);
                }
            }

            if (options.EnableWebSocket)
            {
                if (_webSocketFactory != null)
                {
                    ((ApiClient)apiClient).OpenWebSocket(_webSocketFactory);
                }
            }
        }