diff --git a/CShocker/CShocker.csproj b/CShocker/CShocker.csproj index 6836c68..e27c87d 100644 --- a/CShocker/CShocker.csproj +++ b/CShocker/CShocker.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/CShocker/Class1.cs b/CShocker/Class1.cs deleted file mode 100644 index 94b75c8..0000000 --- a/CShocker/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace CShocker; - -public class Class1 -{ -} \ No newline at end of file diff --git a/CShocker/Ranges/DurationRange.cs b/CShocker/Ranges/DurationRange.cs new file mode 100644 index 0000000..7be5d28 --- /dev/null +++ b/CShocker/Ranges/DurationRange.cs @@ -0,0 +1,9 @@ +namespace CShocker.Ranges; + +public class DurationRange : RandomIntegerRange +{ + public DurationRange(Range range) : base(range, new Range(0, 30000)) + { + + } +} \ No newline at end of file diff --git a/CShocker/Ranges/IntensityRange.cs b/CShocker/Ranges/IntensityRange.cs new file mode 100644 index 0000000..7dacfec --- /dev/null +++ b/CShocker/Ranges/IntensityRange.cs @@ -0,0 +1,9 @@ +namespace CShocker.Ranges; + +public class IntensityRange : RandomIntegerRange +{ + public IntensityRange(Range range) : base(range, new Range(0, 100)) + { + + } +} \ No newline at end of file diff --git a/CShocker/Ranges/RandomIntegerRange.cs b/CShocker/Ranges/RandomIntegerRange.cs new file mode 100644 index 0000000..89800e5 --- /dev/null +++ b/CShocker/Ranges/RandomIntegerRange.cs @@ -0,0 +1,21 @@ +namespace CShocker.Ranges; + +public abstract class RandomIntegerRange +{ + private readonly Range _range; + internal RandomIntegerRange(Range range, Range limits) + { + if (range.Max - range.Min < 0) + throw new ArgumentException("Min has to be less or equal Max"); + if (range.Min < limits.Min || range.Min > limits.Max) + throw new ArgumentOutOfRangeException(nameof(limits.Min), "Min has to be withing Range 0-100"); + if (range.Max < limits.Min || range.Max > limits.Max) + throw new ArgumentOutOfRangeException(nameof(range.Max), "Max has to be withing Range 0-100"); + this._range = range; + } + + internal int GetRandomRangeValue() + { + return Random.Shared.Next(_range.Min, _range.Max); + } +} \ No newline at end of file diff --git a/CShocker/Ranges/Range.cs b/CShocker/Ranges/Range.cs new file mode 100644 index 0000000..3688947 --- /dev/null +++ b/CShocker/Ranges/Range.cs @@ -0,0 +1,12 @@ +namespace CShocker.Ranges; + +public struct Range +{ + public short Min, Max; + + public Range(short min, short max) + { + Min = min; + Max = max; + } +} \ No newline at end of file diff --git a/CShocker/Shockers/Abstract/HTTPShocker.cs b/CShocker/Shockers/Abstract/HTTPShocker.cs new file mode 100644 index 0000000..85d80e0 --- /dev/null +++ b/CShocker/Shockers/Abstract/HTTPShocker.cs @@ -0,0 +1,12 @@ +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers.Abstract; + +internal abstract class HttpShocker : Shocker +{ + public HttpShocker(HttpShockerSettings settings, ILogger? logger = null) : base(settings, logger) + { + + } +} \ No newline at end of file diff --git a/CShocker/Shockers/Abstract/SerialShocker.cs b/CShocker/Shockers/Abstract/SerialShocker.cs new file mode 100644 index 0000000..8ea292e --- /dev/null +++ b/CShocker/Shockers/Abstract/SerialShocker.cs @@ -0,0 +1,12 @@ +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers.Abstract; + +internal abstract class SerialShocker : Shocker +{ + protected SerialShocker(SerialShockerSettings shockerSettings, ILogger? logger = null) : base(shockerSettings, logger) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/CShocker/Shockers/Abstract/Shocker.cs b/CShocker/Shockers/Abstract/Shocker.cs new file mode 100644 index 0000000..56ed61c --- /dev/null +++ b/CShocker/Shockers/Abstract/Shocker.cs @@ -0,0 +1,35 @@ +using CShocker.Shockers.ShockerSettings.Abstract; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers.Abstract +; + +internal abstract class Shocker +{ + protected readonly AShockerSettings ShockerSettings; + protected readonly ILogger? Logger; + + internal enum ControlAction { Beep, Vibrate, Shock, Nothing } + + internal void Control(ControlAction action, string? shockerId = null, int? intensity = null, int? duration = null) + { + int i = intensity ?? ShockerSettings.Intensity.GetRandomRangeValue(); + int d = duration ?? ShockerSettings.Duration.GetRandomRangeValue(); + this.Logger?.Log(LogLevel.Information, $"{action} {(intensity is not null ? $"Overwrite {i}" : $"{i}")} {(duration is not null ? $"Overwrite {d}" : $"{d}")}"); + if (action is ControlAction.Nothing) + return; + if(shockerId is null) + foreach (string shocker in ShockerSettings.ShockerIds) + ControlInternal(action, shocker, i, d); + else + ControlInternal(action, shockerId, i, d); + } + + protected abstract void ControlInternal(ControlAction action, string shockerId, int intensity, int duration); + + protected Shocker(AShockerSettings shockerSettings, ILogger? logger = null) + { + this.ShockerSettings = shockerSettings; + this.Logger = logger; + } +} \ No newline at end of file diff --git a/CShocker/Shockers/OpenShockHttp.cs b/CShocker/Shockers/OpenShockHttp.cs new file mode 100644 index 0000000..0844626 --- /dev/null +++ b/CShocker/Shockers/OpenShockHttp.cs @@ -0,0 +1,47 @@ +using System.Net.Http.Headers; +using System.Text; +using CShocker.Shockers.Abstract; +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers; + +internal class OpenShockHttp : HttpShocker +{ + protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration) + { + HttpRequestMessage request = new (HttpMethod.Post, $"{((HttpShockerSettings)ShockerSettings).Endpoint}/1/shockers/control") + { + Headers = + { + UserAgent = { new ProductInfoHeaderValue("OpenCS2hock", "1") }, + Accept = { new MediaTypeWithQualityHeaderValue("application/json") } + }, + Content = new StringContent(@"[ { "+ + $"\"id\": \"{shockerId}\"," + + $"\"type\": {ControlActionToByte(action)},"+ + $"\"intensity\": {intensity},"+ + $"\"duration\": {duration}"+ + "}]", Encoding.UTF8, new MediaTypeHeaderValue("application/json")) + }; + request.Headers.Add("OpenShockToken", ((HttpShockerSettings)ShockerSettings).ApiKey); + HttpResponseMessage response = ((HttpShockerSettings)ShockerSettings).HttpClient.Send(request); + this.Logger?.Log(LogLevel.Debug, $"{request.RequestUri} response: {response.StatusCode}"); + } + + private byte ControlActionToByte(ControlAction action) + { + return action switch + { + ControlAction.Beep => 3, + ControlAction.Vibrate => 2, + ControlAction.Shock => 1, + _ => 0 + }; + } + + internal OpenShockHttp(HttpShockerSettings settings, ILogger? logger = null) : base(settings, logger) + { + + } +} \ No newline at end of file diff --git a/CShocker/Shockers/OpenShockSerial.cs b/CShocker/Shockers/OpenShockSerial.cs new file mode 100644 index 0000000..f36bf6f --- /dev/null +++ b/CShocker/Shockers/OpenShockSerial.cs @@ -0,0 +1,18 @@ +using CShocker.Shockers.Abstract; +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers; + +internal class OpenShockSerial : SerialShocker +{ + public OpenShockSerial(SerialShockerSettings shockerSettings, ILogger? logger = null) : base(shockerSettings, logger) + { + throw new NotImplementedException(); + } + + protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/CShocker/Shockers/PiShockHttp.cs b/CShocker/Shockers/PiShockHttp.cs new file mode 100644 index 0000000..701ebf6 --- /dev/null +++ b/CShocker/Shockers/PiShockHttp.cs @@ -0,0 +1,18 @@ +using CShocker.Shockers.Abstract; +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers; + +internal class PiShockHttp : HttpShocker +{ + public PiShockHttp(HttpShockerSettings settings, ILogger? logger = null) : base(settings, logger) + { + throw new NotImplementedException(); + } + + protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/CShocker/Shockers/PiShockSerial.cs b/CShocker/Shockers/PiShockSerial.cs new file mode 100644 index 0000000..f153c10 --- /dev/null +++ b/CShocker/Shockers/PiShockSerial.cs @@ -0,0 +1,18 @@ +using CShocker.Shockers.Abstract; +using CShocker.Shockers.ShockerSettings; +using Microsoft.Extensions.Logging; + +namespace CShocker.Shockers; + +internal class PiShockSerial : SerialShocker +{ + public PiShockSerial(SerialShockerSettings shockerSettings, ILogger? logger = null) : base(shockerSettings, logger) + { + throw new NotImplementedException(); + } + + protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/CShocker/Shockers/ShockerSettings/Abstract/AShockerSettings.cs b/CShocker/Shockers/ShockerSettings/Abstract/AShockerSettings.cs new file mode 100644 index 0000000..d3d6193 --- /dev/null +++ b/CShocker/Shockers/ShockerSettings/Abstract/AShockerSettings.cs @@ -0,0 +1,10 @@ +using CShocker.Ranges; + +namespace CShocker.Shockers.ShockerSettings.Abstract; + +public abstract record AShockerSettings(string[] ShockerIds, IntensityRange Intensity, DurationRange Duration) +{ + internal readonly string[] ShockerIds = ShockerIds; + internal readonly IntensityRange Intensity = Intensity; + internal readonly DurationRange Duration = Duration; +} \ No newline at end of file diff --git a/CShocker/Shockers/ShockerSettings/HttpShockerSettings.cs b/CShocker/Shockers/ShockerSettings/HttpShockerSettings.cs new file mode 100644 index 0000000..167e0c3 --- /dev/null +++ b/CShocker/Shockers/ShockerSettings/HttpShockerSettings.cs @@ -0,0 +1,10 @@ +using CShocker.Ranges; +using CShocker.Shockers.ShockerSettings.Abstract; + +namespace CShocker.Shockers.ShockerSettings; + +public abstract record HttpShockerSettings(string[] ShockerIds, IntensityRange Intensity, DurationRange Duration, string ApiKey, string Endpoint) : AShockerSettings(ShockerIds, Intensity, Duration) +{ + internal readonly HttpClient HttpClient = new (); + internal readonly string ApiKey = ApiKey, Endpoint = Endpoint; +} \ No newline at end of file diff --git a/CShocker/Shockers/ShockerSettings/SerialShockerSettings.cs b/CShocker/Shockers/ShockerSettings/SerialShockerSettings.cs new file mode 100644 index 0000000..399fae9 --- /dev/null +++ b/CShocker/Shockers/ShockerSettings/SerialShockerSettings.cs @@ -0,0 +1,9 @@ +using CShocker.Ranges; +using CShocker.Shockers.ShockerSettings.Abstract; + +namespace CShocker.Shockers.ShockerSettings; + +public record SerialShockerSettings(string[] ShockerIds, IntensityRange Intensity, DurationRange Duration) : AShockerSettings(ShockerIds, Intensity, Duration) +{ + +} \ No newline at end of file