Ready to test in Fab
This commit is contained in:
@ -1,8 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<RuntimeIdentifiers>win-x64;linux-x64</RuntimeIdentifiers>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<IsWindows Condition="'$([System.Runtime.InteropServices.RuntimeInformation]::IsOSPlatform($([System.Runtime.InteropServices.OSPlatform]::Windows)))' == 'true'">true</IsWindows>
|
||||
@ -19,7 +20,6 @@
|
||||
<DefineConstants>Linux</DefineConstants>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CliWrap" Version="3.6.3" />
|
||||
<PackageReference Include="System.Text.Json" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="7.0.0" />
|
||||
|
7
Shared/DataModels/Result.cs
Normal file
7
Shared/DataModels/Result.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Barcode.Host.Shared.DataModels;
|
||||
|
||||
public class Result<T>
|
||||
{
|
||||
public T? Results { get; set; }
|
||||
public long TotalRows { get; set; }
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace Barcode.Host.Shared.KeyboardMouse.Abstract;
|
||||
|
||||
public interface IAggregateInputReader
|
||||
{
|
||||
event InputReader.RaiseKeyPress OnKeyPress;
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
using Barcode.Host.Shared.KeyboardMouse.Abstract;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public class AggregateInputReader : IDisposable, IAggregateInputReader
|
||||
{
|
||||
private readonly ILogger<InputReader> _InputReaderLogger;
|
||||
|
||||
private Dictionary<string, InputReader>? _Readers = new();
|
||||
|
||||
public event InputReader.RaiseKeyPress? OnKeyPress;
|
||||
|
||||
public AggregateInputReader(ILogger<InputReader> inputReaderLogger)
|
||||
{
|
||||
_InputReaderLogger = inputReaderLogger;
|
||||
|
||||
System.Timers.Timer timer = new()
|
||||
{
|
||||
Interval = 10 * 1000,
|
||||
Enabled = true
|
||||
};
|
||||
timer.Elapsed += (_, _) => Scan();
|
||||
timer.Start();
|
||||
}
|
||||
|
||||
private void ReaderOnOnKeyPress(KeyPressEvent e) => OnKeyPress?.Invoke(e);
|
||||
|
||||
private void Scan()
|
||||
{
|
||||
string[] files = Directory.GetFiles("/dev/input/", "event*");
|
||||
|
||||
foreach (string file in files)
|
||||
{
|
||||
if (_Readers is not null && _Readers.ContainsKey(file))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
InputReader reader = new(file, _InputReaderLogger);
|
||||
|
||||
reader.OnKeyPress += ReaderOnOnKeyPress;
|
||||
|
||||
_Readers?.Add(file, reader);
|
||||
}
|
||||
|
||||
IEnumerable<InputReader>? deadReaders = _Readers?.Values.Where(r => r.Faulted);
|
||||
if (deadReaders is not null)
|
||||
{
|
||||
foreach (InputReader? dr in deadReaders)
|
||||
{
|
||||
_ = _Readers?.Remove(dr.Path);
|
||||
dr.OnKeyPress -= ReaderOnOnKeyPress;
|
||||
dr.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_Readers is not null)
|
||||
{
|
||||
foreach (InputReader d in _Readers.Values)
|
||||
{
|
||||
d.OnKeyPress -= ReaderOnOnKeyPress;
|
||||
d.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
_Readers = null;
|
||||
}
|
||||
}
|
@ -2,66 +2,52 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public static class DeviceReader
|
||||
{
|
||||
public static IEnumerable<LinuxDevice> Get(string path = "/proc/bus/input/devices")
|
||||
|
||||
public static IEnumerable<LinuxDevice> Get(string path)
|
||||
{
|
||||
List<LinuxDevice> devices = new();
|
||||
|
||||
using FileStream filestream = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
using StreamReader reader = new(filestream);
|
||||
|
||||
LinuxDevice linuxDevice = new();
|
||||
while (!reader.EndOfStream)
|
||||
List<LinuxDevice> linuxDevices = new();
|
||||
using FileStream filestream = new(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
using StreamReader streamReader = new(filestream);
|
||||
while (!streamReader.EndOfStream)
|
||||
{
|
||||
string? line = reader.ReadLine();
|
||||
|
||||
string? line = streamReader.ReadLine();
|
||||
if (string.IsNullOrWhiteSpace(line))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(linuxDevice.Name))
|
||||
{
|
||||
devices.Add(linuxDevice);
|
||||
linuxDevices.Add(linuxDevice);
|
||||
linuxDevice = new LinuxDevice();
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.StartsWith("I"))
|
||||
ApplyIdentifier(line, linuxDevice);
|
||||
|
||||
else if (line.StartsWith("N"))
|
||||
linuxDevice.Name = line.Substring(9, line.Length - 9 - 1);
|
||||
|
||||
else if (line.StartsWith("P"))
|
||||
linuxDevice.PhysicalPath = line[8..];
|
||||
|
||||
else if (line.StartsWith("S"))
|
||||
linuxDevice.SysFsPath = line[9..];
|
||||
|
||||
else if (line.StartsWith("U"))
|
||||
linuxDevice.UniqueIdentificationCode = line[8..];
|
||||
|
||||
else if (line.StartsWith("H"))
|
||||
linuxDevice.Handlers = line[12..]
|
||||
.Split(" ")
|
||||
.Where(h => !string.IsNullOrWhiteSpace(h))
|
||||
.ToList();
|
||||
|
||||
else if (line.StartsWith("B"))
|
||||
linuxDevice.Bitmaps.Add(line[3..]);
|
||||
}
|
||||
|
||||
return devices;
|
||||
return linuxDevices;
|
||||
}
|
||||
|
||||
private static void ApplyIdentifier(string line, LinuxDevice linuxDevice)
|
||||
{
|
||||
string[] values = line[3..]
|
||||
.Split(" ");
|
||||
|
||||
string[] values = line[3..].Split(" ");
|
||||
foreach (string v in values)
|
||||
{
|
||||
string[] kvp = v.Split("=");
|
||||
|
||||
switch (kvp[0])
|
||||
{
|
||||
case "Bus":
|
||||
@ -79,4 +65,5 @@ public static class DeviceReader
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -4,59 +4,42 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public class InputReader : IDisposable
|
||||
{
|
||||
private readonly ILogger<InputReader> _Logger;
|
||||
|
||||
private long _Ticks;
|
||||
private bool _Disposing;
|
||||
private readonly int _PiOffset;
|
||||
private const int _BufferLength = 24;
|
||||
|
||||
private static readonly int _PiOffset;
|
||||
|
||||
private readonly FileStream? _FileStream;
|
||||
private readonly ILogger<IDisposable> _Logger;
|
||||
private readonly byte[] _Buffer = new byte[_BufferLength];
|
||||
|
||||
private FileStream? _Stream;
|
||||
private bool _Disposing;
|
||||
|
||||
public delegate void RaiseKeyPress(KeyPressEvent e);
|
||||
|
||||
public delegate void RaiseMouseMove(MouseMoveEvent e);
|
||||
|
||||
public event RaiseKeyPress? OnKeyPress;
|
||||
|
||||
public event RaiseMouseMove? OnMouseMove;
|
||||
|
||||
public string Path { get; }
|
||||
|
||||
public string Path { get; init; }
|
||||
public bool Faulted { get; private set; }
|
||||
|
||||
static InputReader()
|
||||
{
|
||||
if (RunningOnRaspberryPi())
|
||||
{
|
||||
_PiOffset = -8;
|
||||
}
|
||||
}
|
||||
public event RaiseKeyPress? OnKeyPress;
|
||||
public event RaiseMouseMove? OnMouseMove;
|
||||
|
||||
public InputReader(
|
||||
string path,
|
||||
ILogger<InputReader> logger)
|
||||
{
|
||||
_Logger = logger;
|
||||
public delegate void RaiseKeyPress(KeyPressEvent e);
|
||||
public delegate void RaiseMouseMove(MouseMoveEvent e);
|
||||
|
||||
public InputReader(string path, ILogger<IDisposable> logger)
|
||||
{
|
||||
Path = path;
|
||||
|
||||
_Logger = logger;
|
||||
if (RunningOnRaspberryPi())
|
||||
_PiOffset = -8;
|
||||
try
|
||||
{
|
||||
_Stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
}
|
||||
{ _FileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); }
|
||||
catch (UnauthorizedAccessException ex)
|
||||
{
|
||||
_Logger.LogError(ex, "Current user doesn't have permissions to access input data. Add user to input group to correct this error");
|
||||
logger.LogError(ex, "Current user doesn't have permissions to access input data. Add user to input group to correct this error");
|
||||
Faulted = true;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_Logger.LogWarning(ex, $"Error occurred while trying to build stream for {path}");
|
||||
logger.LogWarning(ex, $"Error occurred while trying to build stream for {path}");
|
||||
Faulted = true;
|
||||
}
|
||||
|
||||
_ = Task.Run(Run);
|
||||
}
|
||||
|
||||
@ -66,33 +49,27 @@ public class InputReader : IDisposable
|
||||
{
|
||||
if (_Disposing)
|
||||
break;
|
||||
|
||||
try
|
||||
{
|
||||
if (!Faulted && _Stream is not null)
|
||||
{
|
||||
_ = _Stream.Read(_Buffer, 0, _BufferLength);
|
||||
}
|
||||
if (!Faulted && _FileStream is not null)
|
||||
_ = _FileStream.Read(_Buffer, 0, _BufferLength);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
_Logger.LogInformation(ex, $"Error occured while trying to read from the stream for {Path}");
|
||||
Faulted = true;
|
||||
}
|
||||
|
||||
EventType type = GetEventType();
|
||||
short code = GetCode();
|
||||
int value = GetValue();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case EventType.EV_SYN:
|
||||
_Ticks = DateTime.Now.Ticks;
|
||||
break;
|
||||
case EventType.EV_KEY:
|
||||
HandleKeyPressEvent(code, value);
|
||||
HandleKeyPressEvent();
|
||||
break;
|
||||
case EventType.EV_REL:
|
||||
MouseAxis axis = (MouseAxis)code;
|
||||
MouseMoveEvent e = new(axis, value);
|
||||
OnMouseMove?.Invoke(e);
|
||||
HandleMouseMoveEvent();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -107,9 +84,7 @@ public class InputReader : IDisposable
|
||||
_Buffer[22 + _PiOffset],
|
||||
_Buffer[23 + _PiOffset]
|
||||
};
|
||||
|
||||
int value = BitConverter.ToInt32(valueBits, 0);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -120,9 +95,7 @@ public class InputReader : IDisposable
|
||||
_Buffer[18 + _PiOffset],
|
||||
_Buffer[19 + _PiOffset]
|
||||
};
|
||||
|
||||
short code = BitConverter.ToInt16(codeBits, 0);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
@ -133,27 +106,35 @@ public class InputReader : IDisposable
|
||||
_Buffer[16 + _PiOffset],
|
||||
_Buffer[17 + _PiOffset]
|
||||
};
|
||||
|
||||
short type = BitConverter.ToInt16(typeBits, 0);
|
||||
|
||||
EventType eventType = (EventType)type;
|
||||
|
||||
return eventType;
|
||||
}
|
||||
|
||||
private void HandleKeyPressEvent(short code, int value)
|
||||
private void HandleKeyPressEvent()
|
||||
{
|
||||
EventCode c = (EventCode)code;
|
||||
KeyState s = (KeyState)value;
|
||||
KeyPressEvent e = new(c, s);
|
||||
OnKeyPress?.Invoke(e);
|
||||
short code = GetCode();
|
||||
int value = GetValue();
|
||||
KeyState keyState = (KeyState)value;
|
||||
EventCode eventCode = (EventCode)code;
|
||||
KeyPressEvent keyPressEvent = new(eventCode, keyState, new TimeSpan(DateTime.Now.Ticks - _Ticks));
|
||||
OnKeyPress?.Invoke(keyPressEvent);
|
||||
}
|
||||
|
||||
private void HandleMouseMoveEvent()
|
||||
{
|
||||
short code = GetCode();
|
||||
int value = GetValue();
|
||||
MouseAxis axis = (MouseAxis)code;
|
||||
MouseMoveEvent e = new(axis, value);
|
||||
OnMouseMove?.Invoke(e);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_Disposing = true;
|
||||
_Stream?.Dispose();
|
||||
_Stream = null;
|
||||
_FileStream?.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
private static bool RunningOnRaspberryPi()
|
||||
@ -163,4 +144,5 @@ public class InputReader : IDisposable
|
||||
bool runningOnPi = text.Any(l => l.Contains("Raspberry Pi"));
|
||||
return runningOnPi;
|
||||
}
|
||||
|
||||
}
|
@ -2,13 +2,16 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public readonly struct KeyPressEvent
|
||||
{
|
||||
public KeyPressEvent(EventCode code, KeyState state)
|
||||
|
||||
public EventCode EventCode { get; init; }
|
||||
public KeyState KeyState { get; init; }
|
||||
public TimeSpan TimeSpan { get; init; }
|
||||
|
||||
public KeyPressEvent(EventCode eventCode, KeyState keyState, TimeSpan timeSpan)
|
||||
{
|
||||
Code = code;
|
||||
State = state;
|
||||
EventCode = eventCode;
|
||||
KeyState = keyState;
|
||||
TimeSpan = timeSpan;
|
||||
}
|
||||
|
||||
public EventCode Code { get; }
|
||||
|
||||
public KeyState State { get; }
|
||||
}
|
@ -2,17 +2,14 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public class LinuxDevice
|
||||
{
|
||||
|
||||
public List<string> Bitmaps { get; set; } = new();
|
||||
public List<string> Handlers { get; set; } = new();
|
||||
public LinuxDeviceIdentifier Identifier { get; set; } = new();
|
||||
|
||||
public string? Name { get; set; }
|
||||
|
||||
public string? PhysicalPath { get; set; }
|
||||
|
||||
public string? SysFsPath { get; set; }
|
||||
|
||||
public string? UniqueIdentificationCode { get; set; }
|
||||
|
||||
public List<string> Handlers { get; set; } = new();
|
||||
|
||||
public List<string> Bitmaps { get; set; } = new();
|
||||
}
|
@ -2,11 +2,10 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public class LinuxDeviceIdentifier
|
||||
{
|
||||
|
||||
public string? Bus { get; set; }
|
||||
|
||||
public string? Vendor { get; set; }
|
||||
|
||||
public string? Product { get; set; }
|
||||
|
||||
public string? Vendor { get; set; }
|
||||
public string? Version { get; set; }
|
||||
|
||||
}
|
@ -2,13 +2,14 @@ namespace Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
public readonly struct MouseMoveEvent
|
||||
{
|
||||
|
||||
public int Amount { get; }
|
||||
public MouseAxis Axis { get; }
|
||||
|
||||
public MouseMoveEvent(MouseAxis axis, int amount)
|
||||
{
|
||||
Axis = axis;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public MouseAxis Axis { get; }
|
||||
|
||||
public int Amount { get; }
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
using CliWrap;
|
||||
using CliWrap.Buffered;
|
||||
|
||||
namespace Barcode.Host.Shared.Linux;
|
||||
|
||||
public class LinuxGroupManager : ILinuxGroupManager
|
||||
{
|
||||
public async Task<bool> IsInInputGroup()
|
||||
{
|
||||
BufferedCommandResult result = await Cli.Wrap("id")
|
||||
.ExecuteBufferedAsync();
|
||||
|
||||
string output = result.StandardOutput;
|
||||
|
||||
const StringSplitOptions options = StringSplitOptions.RemoveEmptyEntries;
|
||||
bool inInputGroup = output.Split(new[] { ' ' }, options)
|
||||
.First(p => p.StartsWith("groups"))
|
||||
.Remove(0, "groups".Length)
|
||||
.Split(',', options)
|
||||
.Any(p => p.Contains("input"));
|
||||
|
||||
return inInputGroup;
|
||||
}
|
||||
|
||||
public async Task AddUserToInputGroup(string password)
|
||||
{
|
||||
using CancellationTokenSource cts = new();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
||||
|
||||
_ = await Cli.Wrap("bash")
|
||||
.WithArguments($"-c \"echo '{password}' | sudo -S gpasswd -a $USER input")
|
||||
.ExecuteBufferedAsync(cts.Token);
|
||||
}
|
||||
|
||||
public async Task RebootSystem(string password)
|
||||
{
|
||||
using CancellationTokenSource cts = new();
|
||||
cts.CancelAfter(TimeSpan.FromSeconds(10));
|
||||
|
||||
_ = await Cli.Wrap("bash")
|
||||
.WithArguments($"-c \"echo '{password}' | sudo -S reboot\"")
|
||||
.ExecuteBufferedAsync(cts.Token);
|
||||
}
|
||||
}
|
10
Shared/Models/Stateless/IAggregateInputReader.cs
Normal file
10
Shared/Models/Stateless/IAggregateInputReader.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
namespace Barcode.Host.Shared.Models.Stateless;
|
||||
|
||||
public interface IAggregateInputReader
|
||||
{
|
||||
|
||||
event InputReader.RaiseKeyPress OnKeyPress;
|
||||
|
||||
}
|
14
Shared/Models/Stateless/ILastScanController.cs
Normal file
14
Shared/Models/Stateless/ILastScanController.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace Barcode.Host.Shared.Models.Stateless;
|
||||
|
||||
public interface ILastScanController<T>
|
||||
{
|
||||
|
||||
enum Action : int
|
||||
{
|
||||
Get = 0
|
||||
}
|
||||
|
||||
static string GetRouteName() => nameof(ILastScanController<T>)[1..^10];
|
||||
T GetScan();
|
||||
|
||||
}
|
15
Shared/Models/Stateless/ILastScanService.cs
Normal file
15
Shared/Models/Stateless/ILastScanService.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using Barcode.Host.Shared.DataModels;
|
||||
using Barcode.Host.Shared.KeyboardMouse;
|
||||
|
||||
namespace Barcode.Host.Shared.Models.Stateless;
|
||||
|
||||
public interface ILastScanService
|
||||
{
|
||||
|
||||
void Clear();
|
||||
int GetCount();
|
||||
Result<string> GetScan();
|
||||
void Add(EventCode eventCode, char @char);
|
||||
List<(EventCode, char)> IncludeEventCodes();
|
||||
|
||||
}
|
@ -1,10 +1,10 @@
|
||||
namespace Barcode.Host.Shared.Linux;
|
||||
namespace Barcode.Host.Shared.Models.Stateless;
|
||||
|
||||
public interface ILinuxGroupManager
|
||||
{
|
||||
Task<bool> IsInInputGroup();
|
||||
|
||||
Task<bool> IsInInputGroup();
|
||||
Task RebootSystem(string password);
|
||||
Task AddUserToInputGroup(string password);
|
||||
|
||||
Task RebootSystem(string password);
|
||||
}
|
10
Shared/Models/Stateless/ISerialService.cs
Normal file
10
Shared/Models/Stateless/ISerialService.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace Barcode.Host.Shared.Models.Stateless;
|
||||
|
||||
public interface ISerialService
|
||||
{
|
||||
|
||||
void Open();
|
||||
void Close();
|
||||
void SerialPortWrite(int count, string raw);
|
||||
|
||||
}
|
@ -32,7 +32,7 @@ internal abstract class WorkingDirectory
|
||||
{
|
||||
if (!Directory.Exists(result))
|
||||
_ = Directory.CreateDirectory(result);
|
||||
traceFile = string.Concat(result, @"\", DateTime.Now.Ticks, ".txt");
|
||||
traceFile = Path.Combine(result, $"{DateTime.Now.Ticks}.txt");
|
||||
File.WriteAllText(traceFile, traceFile);
|
||||
File.Delete(traceFile);
|
||||
break;
|
||||
|
Reference in New Issue
Block a user