scripts/AlsResetScript.txt

265 lines
6.9 KiB
Plaintext
Raw Normal View History

2021-10-19 08:35:44 +00:00
using System;
using System.Threading.Tasks;
using MDP.SID.Scripting.Service;
using GrpcScriptService;
using Newtonsoft.Json;
using System.Threading;
using System.Net.Http;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Collections.Concurrent;
using Timer = System.Timers.Timer;
public class Interval
{
public TimeSpan Start { get; set; }
public TimeSpan End { get; set; }
public string Name { get; set; }
}
private readonly Interval[] _accessIntervals =
{
// Explanation -> TimeSpan(int hours, int minutes, int seconds)
new Interval {Start = new TimeSpan(16, 55, 0), End = new TimeSpan(17, 00, 0), Name = "Breakfast"},
new Interval {Start = new TimeSpan(17, 00, 0), End = new TimeSpan(17, 05, 0), Name = "Lunch"},
new Interval {Start = new TimeSpan(17, 05, 0), End = new TimeSpan(17, 10, 0), Name = "Dinner"}
};
private readonly string[] _canteenDoors =
{
"CANTEEN", "CANTEEN-DOOR-R-TUR-2 Ent"
};
private string _path;
private SemaphoreSlim _semaphoreSlim = new(1);
public readonly TimeSpan AccessLevelsResetTime = new(17, 11, 0);
private Timer _timer;
private static ConcurrentDictionary<int, IList<string>> _failedAddOrUpdate = new();
private async Task ResetUsersAccessLevelsAsync()
{
try
{
await _semaphoreSlim.WaitAsync();
if (File.Exists(_path) is false)
{
Context.LogError("Users file not found");
return;
}
var alNames = _accessIntervals.Select(a => a.Name);
var accessLevels = await Context.GetAccessLevelsAsync();
var updateEntities = accessLevels
.Where(a => alNames.Contains(a.Name))
.Select(a => new EntityUpdate { Id = a.Id, Update = true });
var text = await File.ReadAllTextAsync(_path);
var users = JsonConvert.DeserializeObject<Dictionary<int, IList<string>>>(text);
if (users is null || users.Any() is false)
{
Context.LogWarning("Users file empty");
return;
}
var userIds = users.Keys.ToArray();
var configuration = new BulkUpdateUser();
configuration.AccessLevels.AddRange(updateEntities);
await Context.BulkUpdateUsersAsync(0, userIds.Length, userIds, configuration);
File.Delete(_path);
Context.LogInformation("Users file deleted after bulk update operation");
}
catch (Exception ex)
{
Context.LogError($"Failed reset users access levels. Exception: {ex.Message}");
}
finally
{
_semaphoreSlim.Release();
}
}
private void AddOrUpdateUser(int userId, string accessLevel)
{
try
{
_semaphoreSlim.Wait();
Dictionary<int, IList<string>> users;
if (File.Exists(_path) is false)
{
users = new Dictionary<int, IList<string>>();
}
else
{
var text = File.ReadAllText(_path);
users = JsonConvert.DeserializeObject<Dictionary<int, IList<string>>>(text);
// no content
if (users is null)
{
users = new Dictionary<int, IList<string>>();
}
}
AddFromFailed(users);
if (users.TryGetValue(userId, out var accessLevels))
{
if (accessLevels.Contains(accessLevel) is false)
{
accessLevels.Add(accessLevel);
}
}
else
{
users.Add(userId, new List<string> { accessLevel });
}
var output = JsonConvert.SerializeObject(users);
File.WriteAllText(_path, output);
_failedAddOrUpdate.Clear();
}
catch (Exception ex)
{
Context.LogError($"Failed add or update user with Id: {userId} al: {accessLevel}. Exception: {ex.Message}");
AddToFailed(userId, accessLevel);
}
finally
{
_semaphoreSlim.Release();
}
}
private void AddToFailed(int userId, string accessLevel)
{
if (_failedAddOrUpdate.TryGetValue(userId, out var als))
{
if (als.Contains(accessLevel)) return;
var newAls = new List<string>(als) { accessLevel };
_failedAddOrUpdate.TryUpdate(userId, newAls, als);
}
else
{
_failedAddOrUpdate.TryAdd(userId, new List<string> { accessLevel });
}
}
private void AddFromFailed(Dictionary<int, IList<string>> users)
{
foreach (var user in _failedAddOrUpdate)
{
if (users.TryGetValue(user.Key, out var accessLevels))
{
foreach (var al in user.Value)
{
if (accessLevels.Contains(al)) continue;
accessLevels.Add(al);
}
}
else
{
users.Add(user.Key, user.Value);
}
}
}
private async void EventReceived(Event received)
{
if (received.TypeUid == "891adc81-6991-44c2-8aa4-f7a0792f77f5" && _canteenDoors.Contains(received.DoorName))
{
var accessTime = received.Time.ToDateTime().ToLocalTime().TimeOfDay;
var interval = _accessIntervals.FirstOrDefault(a => a.End >= accessTime && a.Start <= accessTime);
if (interval is null)
{
Context.LogDebug($"Al interval by access time not found. Access time: {accessTime}");
return;
}
var userAccessLevels = await Context.GetUserAccessLevelsAsync((int)received.UserId);
var userAccessLevel = userAccessLevels.FirstOrDefault(a => a.Name == interval.Name);
if (userAccessLevel is null)
{
Context.LogWarning($"Al for user with Id: {(int)received.UserId} not found");
return;
}
await Context.DeleteUserAccessLevelAsync(userAccessLevel.Id);
Context.LogDebug($"Al: {userAccessLevel.Name} removed for user with Id: {(int)received.UserId}");
AddOrUpdateUser((int)received.UserId, userAccessLevel.Name);
}
}
private async Task OnResetEvent()
{
_timer.Interval = new TimeSpan(24, 0, 0).TotalMilliseconds;
_timer.Start();
Context.LogInformation("Reset users al's event raised");
await ResetUsersAccessLevelsAsync();
}
Context.OnEventReceived += EventReceived;
var timeToReset = AccessLevelsResetTime - DateTime.Now.TimeOfDay;
if (timeToReset.CompareTo(TimeSpan.Zero) < 0)
{
timeToReset = new TimeSpan(1, AccessLevelsResetTime.Hours, AccessLevelsResetTime.Minutes, AccessLevelsResetTime.Seconds) - DateTime.Now.TimeOfDay;
}
Context.LogDebug($"Time until al reset first time hit (milliseconds): {timeToReset}");
_timer = new Timer(timeToReset.TotalMilliseconds);
_timer.Elapsed += async (_, _) => await OnResetEvent();
_timer.AutoReset = false;
_timer.Start();
var scriptFilesPath = await Context.GetScriptFilesPathAsync();
_path = Path.Combine(scriptFilesPath, "Canteen.txt");
CancellationToken.WaitHandle.WaitOne();
_timer.Stop();
_timer.Dispose();
Context.LogInformation("Script stopped");