private async void _alarmRepository_AlarmChanged(object sender, AlarmChangedEventArgs e) { // Only handle closed alarms if (e.Alarm.StateId != BuiltInAlarmStates.Closed) { return; } // If all alarms for this source and event type are closed in VMS, close corresponding alarm in the Demo Access Control system var doorId = e.Alarm.ExternalSourceId; var eventTypeId = e.Alarm.ExternalEventTypeId; var alarms = _alarmRepository.GetAlarmsForSource(doorId, eventTypeId, false); if (!alarms.Any()) { try { await _client.CloseAlarmAsync(doorId, eventTypeId); } catch (DemoApplicationClientException ex) { // A retry mechanism would probably be in order... ACUtil.Log(true, "DemoACPlugin.AlarmManager", "Error closing alarm in Demo Access Control system: " + ex.Message); } } }
public override ACCredentialHolderSearchResults SearchCredentialHolders(string searchString, int searchLimit) { var partialResult = false; var searchResult = new List <ACCredentialHolderSearchResult>(); try { var credentialHolders = _client.SearchCredentialHolders(searchString); foreach (var ch in credentialHolders) { searchResult.Add(new ACCredentialHolderSearchResult(ch.CredentialHolderId.ToString(), ch.CredentialHolderName, ch.Roles)); } // Demo Access Control system does not support search limit, so we truncate the result if (searchResult.Count > searchLimit) { searchResult.RemoveRange(searchLimit, searchResult.Count - searchLimit); partialResult = true; } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.CredentialHolderManager", "Error searching credential holders: " + ex.Message); } return(new ACCredentialHolderSearchResults(searchResult, partialResult)); }
public sealed override void ApplyConfiguration(ACConfiguration configuration) { ACUtil.Log(false, "DemoACPlugin.ConfigurationManager", "Configuration applied."); // Store the server id - used for connected/disconnected events and when rebuilding the configuration _client.ServerId = configuration.ACServer.Id; UpdateDoorEnabledState(configuration); UpdateEventTypeEnabledState(configuration); // Other plug-ins might e.g. need to connect to peers listed in the configuration, // or need to look up elements to determine the type or read some custom properties. }
public override void Close() { _commandManager.Close(); _configurationManager.Close(); _connectionManager.Close(); _credentialHolderManager.Close(); _eventManager.Close(); _stateManager.Close(); _alarmSynchronizer.Close(); _client.Close(); ACUtil.Log(false, "DemoACPlugin.DemoAccessControlSystem", "Access control system unloaded."); }
/// <summary> /// Validate user credentials for personalized log-in. /// </summary> public override ACUserCredentialsValidationResult ValidateUserCredentials(string username, string password) { try { var valid = _client.CheckCredentials(username, password); return(new ACUserCredentialsValidationResult(valid)); } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.ConnectionManager", "Error validating user credentials: " + ex.Message); return(new ACUserCredentialsValidationResult(false)); } }
private async Task FetchPersonalizedConfigurationAsync(string username, string password, long latestVersion) { try { FireFetchPersonalizedConfigurationStatusChanged(new ACFetchPersonalizedConfigurationStatusChangedEventArgs(0, "Waiting for connection to be established", username)); var authorized = await _client.CheckCredentialsAsync(username, password); if (!authorized) { FireFetchPersonalizedConfigurationStatusChanged(new ACFetchPersonalizedConfigurationStatusChangedEventArgs("Invalid username or password.", username)); return; } FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.25, "Retrieving door controllers...")); var doorControllers = await _client.GetDoorControllersAsync(username, password); await Task.Delay(500); // Delay a bit for demonstration FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.5, "Retrieving doors...")); var doors = await _client.GetDoorsAsync(username, password); await Task.Delay(500); // Delay a bit for demonstration FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.75, "Retrieving event types...")); var eventTypes = await _client.GetEventTypesAsync(username, password); await Task.Delay(500); // Delay a bit for demonstration var configuration = BuildConfiguration(doorControllers, doors, eventTypes); if (configuration != null) { // Done FireFetchPersonalizedConfigurationStatusChanged(new ACFetchPersonalizedConfigurationStatusChangedEventArgs(configuration, username, latestVersion.ToString())); } else { FireFetchPersonalizedConfigurationStatusChanged(new ACFetchPersonalizedConfigurationStatusChangedEventArgs("Invalid configuration.", username)); } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.ConfigurationManager", "Error fetching configuration for user " + username + ": " + ex.Message); FireFetchPersonalizedConfigurationStatusChanged(new ACFetchPersonalizedConfigurationStatusChangedEventArgs("Error communicating with the Demo Application.", username)); } }
public override ACCredentialHolder GetCredentialHolder(string credentialHolderId) { // This is called when credential holder isn't already cached - look up synchronously try { var credentialHolderDecriptor = _client.GetCredentialHolder(credentialHolderId); if (credentialHolderDecriptor != null) { return(TypeConverter.ToACCredentialHolder(credentialHolderDecriptor, _systemProperties)); } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.CredentialHolderManager", "Error looking up credential holder: " + ex.Message); } return(null); }
public override void Init(ACConfiguration configuration) { ACUtil.Log(false, "DemoACPlugin.DemoAccessControlSystem", "Initializing access control system."); _systemProperties = new SystemProperties(); _client = new DemoClient(_systemProperties); _commandManager = new CommandManager(_systemProperties, _client); _configurationManager = new ConfigurationManager(_systemProperties, _client, configuration); _connectionManager = new ConnectionManager(_client); _credentialHolderManager = new CredentialHolderManager(_systemProperties, _client); _eventManager = new EventManager(_client); _stateManager = new StateManager(_client); // Pass the ACAlarmRepository to a separate class for handling two-way alarm synchronization, if needed _alarmSynchronizer = new AlarmSynchronizer(_client, ACAlarmRepository); }
private async void _client_CredentialHolderChanged(object sender, CredentialHolderChangedEventArgs e) { // Fetch the updated credential holder asynchronously before calling FireCredentialHoldersChanged try { var credentialHolderDecriptor = await _client.GetCredentialHolderAsync(e.CredentialHolderId); if (credentialHolderDecriptor != null) { var credentialHolder = TypeConverter.ToACCredentialHolder(credentialHolderDecriptor, _systemProperties); FireCredentialHoldersChanged(new[] { credentialHolder }); } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.CredentialHolderManager", "Error updating credential holder: " + ex.Message); } }
private async Task RefreshStateAsync(string id, CancellationToken cancellationToken) { try { // Only allow one concurrent call to the access control system (VMS will likely request status for all doors on startup) await _resolveStateSemaphore.WaitAsync(cancellationToken); try { // Check if status was already updated var state = GetState(id); if (state == null) { try { var doorStatus = await _client.GetDoorStatusAsync(id); cancellationToken.ThrowIfCancellationRequested(); if (doorStatus != null) { state = TypeConverter.ToACState(doorStatus); UpdateState(state); FireStatesChanged(new[] { state }); } } catch (DemoApplicationClientException ex) { // Should probably retry on failure ACUtil.Log(true, "DemoACPlugin.StateManager", "Error refreshing state for door " + id + ": " + ex.Message); } } } finally { _resolveStateSemaphore.Release(); } } catch (OperationCanceledException) { } }
/// <summary> /// Execute a command. Used when personalized log-in is enabled. /// </summary> public override ACCommandResult ExecuteCommand(string operationableInstance, string commandType, string username, string password, string vmsUsername) { try { if (commandType == CommandTypes.DoorLock.Id) { _client.LockDoor(operationableInstance, username, password, vmsUsername); } else if (commandType == CommandTypes.DoorUnlock.Id) { _client.UnlockDoor(operationableInstance, username, password, vmsUsername); } else { return(new ACCommandResult(false, "Invalid command.")); } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.CommandManager", "Error executing command " + commandType + " on door " + operationableInstance + ": " + ex.Message); return(new ACCommandResult(false, ex.Message)); } return(new ACCommandResult(true)); }
private ACConfiguration BuildConfiguration(DoorControllerDescriptor[] doorControllers, DoorDescriptor[] doors, EventDescriptor[] eventDescriptors) { var elements = new List <ACElement>(); // Add element types elements.Add(ElementTypes.ServerType); elements.Add(ElementTypes.DoorControllerType); // Add event types elements.AddRange(EventTypes.ServerEventTypes); foreach (var eventDescriptor in eventDescriptors) { var acEventType = TypeConverter.ToACEventType(eventDescriptor, !_disabledEventTypes.Contains(eventDescriptor.EventId)); elements.Add(acEventType); } // Add state types elements.AddRange(StateTypes.ServerStateTypes); elements.AddRange(StateTypes.DoorStateTypes); // Add command types elements.AddRange(CommandTypes.DoorCommands); // Look up the all events, which can be fired on a door // OBS: In the Demo Access Control application, events with source "DoorController" are actually fired on the door. var doorEventTypeIds = eventDescriptors.Where(e => e.SourceType == "Door" || e.SourceType == "DoorController").Select(ed => ed.EventId.ToString()); elements.Add(ElementTypes.CreateDoorType(doorEventTypeIds)); // Look up the all events, which can be fired on an access point var apEventTypeIds = eventDescriptors.Where(ed => ed.SourceType == "AccessPoint").Select(ed => ed.EventId.ToString()); elements.Add(ElementTypes.CreateAccessPointType(apEventTypeIds)); // Add server element elements.Add(TypeConverter.CreateACServer(_client.ServerId, _systemProperties.Address)); // Add door controllers foreach (var doorController in doorControllers) { elements.Add(TypeConverter.ToACUnit(doorController)); } // Add doors and access points foreach (var door in doors) { door.Enabled = !_disabledDoors.Contains(door.DoorId); elements.AddRange(TypeConverter.ToACUnits(door)); } try { return(ACConfiguration.CreateACConfiguration(DateTime.UtcNow, elements)); } catch (ACConfigurationException ex) { ACUtil.Log(true, "DemoACPlugin.ConfigurationManager", "Error building configuration: " + ex.Message); return(null); } }
private async Task FetchConfigurationAsync(CancellationToken cancellationToken) { try { FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0, "Connecting to demo system...")); // Check admin credentials (not actually required) var valid = await _client.CheckCredentialsAsync(_systemProperties.AdminUser, _systemProperties.AdminPassword); await Task.Delay(500, cancellationToken); // Delay a bit for show cancellationToken.ThrowIfCancellationRequested(); if (!valid) { FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs("Invalid credentials.")); return; } FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.25, "Retrieving door controllers...")); var doorControllers = await _client.GetDoorControllersAsync(); await Task.Delay(500, cancellationToken); // Delay a bit for demonstration cancellationToken.ThrowIfCancellationRequested(); FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.5, "Retrieving doors...")); var doors = await _client.GetDoorsAsync(); await Task.Delay(500, cancellationToken); // Delay a bit for demonstration cancellationToken.ThrowIfCancellationRequested(); FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(0.75, "Retrieving event types...")); var eventTypes = await _client.GetEventTypesAsync(); await Task.Delay(500, cancellationToken); // Delay a bit for demonstration cancellationToken.ThrowIfCancellationRequested(); var configuration = BuildConfiguration(doorControllers, doors, eventTypes); if (configuration != null) { // Done FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs(configuration)); } else { FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs("Invalid configuration.")); } } catch (DemoApplicationClientException ex) { ACUtil.Log(true, "DemoACPlugin.ConfigurationManager", "Error fetching configuration: " + ex.Message); FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs("Error communicating with the Demo Application.")); } catch (OperationCanceledException) { FireFetchConfigurationStatusChanged(new ACFetchConfigurationStatusChangedEventArgs("Fetching configuration canceled.")); } }
private async Task EventPollingAsync(CancellationToken cancellationToken) { // Demo Access Control system uses sequence numbers based on ticks, so we initialize it to current time var seqNr = DateTime.UtcNow.Ticks; while (!cancellationToken.IsCancellationRequested) { try { // Get events from the Demo Access Control system var events = await TryCall(client => client.GetEventsAsync(_systemProperties.AdminUser, _systemProperties.AdminPassword, 5000, seqNr, _systemProperties.EventPollingCount)); if (!_connected) { _connected = true; ACUtil.Log(false, "DemoACPlugin.DemoClient", "Connected to " + _systemProperties.Address); Connected(this, EventArgs.Empty); } if (events.Any()) { seqNr = events.Last().SequenceNumber + 1; } foreach (var baseEvent in events) { var dse = baseEvent as DoorStatusEvent; if (dse != null) { var state = TypeConverter.ToACState(dse.Status); StateChanged(this, new StateChangedEventArgs(state)); continue; } var dce = baseEvent as DoorControllerEvent; if (dce != null) { var acEvent = TypeConverter.ToACEvent(dce); EventTriggered(this, new EventTriggeredEventArgs(acEvent)); continue; } var cce = baseEvent as CredentialHolderChangedEvent; if (cce != null) { CredentialHolderChanged(this, new CredentialHolderChangedEventArgs(cce.CredentialHolderId.ToString())); continue; } var uce = baseEvent as UserChangedEvent; if (uce != null) { UserRightsChanged(this, new UserRightsChangedEventArgs(uce.UserId, uce.UserName, uce.LastChanged)); continue; } } // Get alarm to clear from the Demo Access Control system var alarmsToClear = await TryCall(client => client.GetAlarmsToClearAsync(_systemProperties.AdminUser, _systemProperties.AdminPassword)); foreach (var clearAlarmCmd in alarmsToClear) { AlarmCleared(this, new AlarmClearedEventArgs(clearAlarmCmd.DoorId.ToString(), clearAlarmCmd.EventTypeId.ToString())); } } catch (Exception ex) { // Connection broken. if (_connected) { _connected = false; ACUtil.Log(true, "DemoACPlugin.DemoClient", "Connection to " + _systemProperties.Address + " failed: " + ex.Message); Disconnected(this, EventArgs.Empty); } } try { await Task.Delay(_systemProperties.EventPollingPeriodMs, cancellationToken); } catch (OperationCanceledException) { } } _connected = false; ACUtil.Log(false, "DemoACPlugin.DemoClient", "Connection to " + _systemProperties.Address + " closed."); // Don't close the client on Disconnect - wait for Close }