-
Notifications
You must be signed in to change notification settings - Fork 0
feat: min/max settings, multiple shockers per share code, and new API endpoints #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,16 +6,20 @@ namespace OpenShock.Desktop.Modules.Interception.HostsFile; | |
| public sealed class HostsFileManager | ||
| { | ||
| private const string HostsPath = @"C:\Windows\System32\drivers\etc\hosts"; | ||
| private const string HostEntry = "127.0.0.1 do.pishock.com"; | ||
| private const string Marker = "# OpenShock Interception"; | ||
|
|
||
| private static readonly string[] HostEntries = | ||
| [ | ||
| $"127.0.0.1 do.pishock.com {Marker}", | ||
| $"127.0.0.1 ps.pishock.com {Marker}" | ||
| ]; | ||
|
|
||
| public bool IsEnabled { get; private set; } | ||
|
|
||
| public async Task EnableAsync() | ||
| { | ||
| if (IsEnabled) return; | ||
| var line = $"{HostEntry} {Marker}"; | ||
| await RunElevatedHostsCommand($"add \"{line}\""); | ||
| await RunElevatedHostsCommand("add"); | ||
| IsEnabled = true; | ||
| await FlushDns(); | ||
| } | ||
|
|
@@ -44,15 +48,16 @@ public async Task DetectCurrentState() | |
| private static async Task RunElevatedHostsCommand(string action) | ||
| { | ||
| string script; | ||
| if (action.StartsWith("add")) | ||
| if (action == "add") | ||
| { | ||
| var line = action.Substring(4).Trim(); | ||
| var linesArray = string.Join(",", HostEntries.Select(e => $"'{e}'")); | ||
| script = string.Join("\n", | ||
| $"$line = {line};", | ||
| $"$lines = @({linesArray});", | ||
| $"$hostsPath = '{HostsPath}';", | ||
| "$content = Get-Content $hostsPath -Raw -ErrorAction SilentlyContinue;", | ||
| "if ($content -notmatch 'OpenShock Interception') {", | ||
| " Add-Content -Path $hostsPath -Value \"`n$line\" -NoNewline:$false", | ||
| " $toAdd = \"`n\" + ($lines -join \"`n\");", | ||
| " Add-Content -Path $hostsPath -Value $toAdd -NoNewline:$false", | ||
|
Comment on lines
58
to
+60
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The add script appends both host entries only when no Useful? React with 👍 / 👎. |
||
| "}"); | ||
| } | ||
| else | ||
|
|
@@ -104,4 +109,4 @@ private static async Task FlushDns() | |
| // Best-effort DNS flush | ||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,8 +1,10 @@ | ||
| using OpenShock.Desktop.Modules.Interception.Server; | ||
|
|
||
| namespace OpenShock.Desktop.Modules.Interception; | ||
|
|
||
| public sealed class InterceptionConfig | ||
| { | ||
| public ushort Port { get; set; } = 443; | ||
| public bool AutoStart { get; set; } = true; | ||
| public Dictionary<string, Guid> ShareCodeMappings { get; set; } = new(); | ||
| } | ||
| public Dictionary<string, ShareCodeMapping> ShareCodeMappings { get; set; } = new(); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -56,7 +56,7 @@ public async Task Operate() | |
| return; | ||
| } | ||
|
|
||
| if (!_service.Config.ShareCodeMappings.TryGetValue(request.Code, out var shockerId)) | ||
| if (!_service.Config.ShareCodeMappings.TryGetValue(request.Code, out var mapping)) | ||
| { | ||
| _logger.LogError("Share code not mapped to any shocker: {Code}", request.Code); | ||
| HttpContext.Response.StatusCode = 404; | ||
|
|
@@ -65,6 +65,15 @@ await HttpContext.SendStringAsync("Share code not mapped to any shocker", "text/ | |
| return; | ||
| } | ||
|
|
||
| if (mapping.ShockerIds.Count == 0) | ||
| { | ||
| _logger.LogError("Share code has no shockers configured: {Code}", request.Code); | ||
| HttpContext.Response.StatusCode = 404; | ||
| await HttpContext.SendStringAsync("Share code has no shockers configured", "text/plain", | ||
| Encoding.UTF8); | ||
| return; | ||
| } | ||
|
|
||
| var controlType = request.Op switch | ||
| { | ||
| 0 => ControlType.Shock, | ||
|
|
@@ -73,30 +82,27 @@ await HttpContext.SendStringAsync("Share code not mapped to any shocker", "text/ | |
| _ => ControlType.Vibrate | ||
| }; | ||
|
|
||
| var durationMs = (ushort)Math.Clamp(request.Duration * 1000, 300, 30000); | ||
| var intensity = (byte)Math.Clamp(request.Intensity, 1, 100); | ||
| var durationMs = (ushort)Math.Clamp(request.Duration * 1000, mapping.MinDuration * 1000, mapping.MaxDuration * 1000); | ||
| var intensity = (byte)Math.Clamp(request.Intensity, mapping.MinIntensity, mapping.MaxIntensity); | ||
|
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
These clamps assume Useful? React with 👍 / 👎. |
||
|
|
||
| if (request.Intensity <= 0) controlType = ControlType.Stop; | ||
|
|
||
| var controls = new[] | ||
| var controls = mapping.ShockerIds.Select(id => new ShockerControl | ||
| { | ||
| new ShockerControl | ||
| { | ||
| Id = shockerId, | ||
| Type = controlType, | ||
| Intensity = intensity, | ||
| Duration = durationMs | ||
| } | ||
| }; | ||
| Id = id, | ||
| Type = controlType, | ||
| Intensity = intensity, | ||
| Duration = durationMs | ||
| }).ToArray(); | ||
|
|
||
| var customName = request.Name ?? request.Username ?? "PiShock Interception"; | ||
|
|
||
| try | ||
| { | ||
| await _openShockControl.Control(controls, customName); | ||
| _logger.LogInformation( | ||
| "PiShock Do API: control command: {ControlType} {Intensity}% for {Duration}s on shocker {ShockerId} by {Name}", | ||
| controlType, intensity, durationMs / 1000.0, shockerId, customName); | ||
| "PiShock Do API: control command: {ControlType} {Intensity}% for {Duration}s on {ShockerCount} shocker(s) by {Name}", | ||
| controlType, intensity, durationMs / 1000.0, controls.Length, customName); | ||
| await HttpContext.SendStringAsync( | ||
| JsonSerializer.Serialize(new { success = true, message = "Operation Succeeded." }), | ||
| "application/json", Encoding.UTF8); | ||
|
|
@@ -137,7 +143,7 @@ public async Task GetShockerInfo() | |
| return; | ||
| } | ||
|
|
||
| if (!_service.Config.ShareCodeMappings.TryGetValue(request.Code, out var shockerId)) | ||
| if (!_service.Config.ShareCodeMappings.TryGetValue(request.Code, out var mapping)) | ||
| { | ||
| _logger.LogError("Share code not mapped to any shocker: {Code}", request.Code); | ||
| HttpContext.Response.StatusCode = 404; | ||
|
|
@@ -147,15 +153,15 @@ public async Task GetShockerInfo() | |
|
|
||
| var info = new | ||
| { | ||
| clientId = shockerId, | ||
| clientId = mapping.ShockerIds.FirstOrDefault(), | ||
| name = $"Shocker ({request.Code})", | ||
| maxIntensity = 100, | ||
| maxDuration = 15, | ||
| maxIntensity = (int)mapping.MaxIntensity, | ||
| maxDuration = (int)mapping.MaxDuration, | ||
| online = true | ||
| }; | ||
|
|
||
| await HttpContext.SendStringAsync( | ||
| JsonSerializer.Serialize(info), | ||
| "application/json", Encoding.UTF8); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| using System.Text; | ||
| using EmbedIO; | ||
| using EmbedIO.Routing; | ||
| using EmbedIO.WebApi; | ||
|
|
||
| namespace OpenShock.Desktop.Modules.Interception.Server; | ||
|
|
||
| public sealed class HealthWebApiController : WebApiController | ||
| { | ||
| [Route(HttpVerbs.Get, "/Check")] | ||
| public async Task Check() | ||
| { | ||
| HttpContext.Response.StatusCode = 200; | ||
| await HttpContext.SendStringAsync("OK", "text/plain", Encoding.UTF8); | ||
| } | ||
|
|
||
| [Route(HttpVerbs.Get, "/Server")] | ||
| public Task Server() | ||
| { | ||
| HttpContext.Response.StatusCode = 204; | ||
| return Task.CompletedTask; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding
ps.pishock.comto SAN here only affects newly generated certificates;LoadOrCreateServerCertstill returns any existing, unexpiredinterception-server.pfx, so upgraded users keep a cert that only matchesdo.pishock.comand TLS validation forhttps://ps.pishock.comwill fail until they manually delete/regenerate the cert.Useful? React with 👍 / 👎.