Fix OpenShockHttp: Wrong json caused Bad Request
Get OpenShock Shockers from API. Save Shockers for PiShock and OpenShock in different structs Implement Action Queue, to avoid synchronous actions getting lost. Moved SerialPortInfo to own file Created ShockerJsonConverter Better separation of Devices/APIs and Shockers
This commit is contained in:
@ -1,103 +0,0 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using CShocker.Ranges;
|
||||
using CShocker.Shockers.Abstract;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CShocker.Shockers.APIS;
|
||||
|
||||
public class OpenShockHttp : HttpShocker
|
||||
{
|
||||
|
||||
public List<string> GetShockers()
|
||||
{
|
||||
HttpRequestMessage requestDevices = new (HttpMethod.Get, $"{Endpoint}/2/devices")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
|
||||
}
|
||||
};
|
||||
requestDevices.Headers.Add("OpenShockToken", ApiKey);
|
||||
this.Logger?.Log(LogLevel.Debug, $"Requesting {requestDevices.RequestUri}");
|
||||
HttpResponseMessage responseDevices = HttpClient.Send(requestDevices);
|
||||
|
||||
StreamReader deviceStreamReader = new(responseDevices.Content.ReadAsStream());
|
||||
string deviceJson = deviceStreamReader.ReadToEnd();
|
||||
this.Logger?.Log(!responseDevices.IsSuccessStatusCode ? LogLevel.Critical : LogLevel.Debug,
|
||||
$"{requestDevices.RequestUri} response: {responseDevices.StatusCode}\n{deviceJson}");
|
||||
JObject deviceListJObj = JObject.Parse(deviceJson);
|
||||
List<string> deviceIds = new();
|
||||
deviceIds.AddRange(deviceListJObj["data"]!.Children()["id"].Values<string>()!);
|
||||
|
||||
List<string> shockerIds = new();
|
||||
foreach (string deviceId in deviceIds)
|
||||
{
|
||||
HttpRequestMessage requestShockers = new (HttpMethod.Get, $"{Endpoint}/2/devices/{deviceId}/shockers")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
|
||||
}
|
||||
};
|
||||
requestShockers.Headers.Add("OpenShockToken", ApiKey);
|
||||
this.Logger?.Log(LogLevel.Debug, $"Requesting {requestShockers.RequestUri}");
|
||||
HttpResponseMessage response = HttpClient.Send(requestShockers);
|
||||
|
||||
StreamReader shockerStreamReader = new(response.Content.ReadAsStream());
|
||||
string shockerJson = shockerStreamReader.ReadToEnd();
|
||||
this.Logger?.Log(!response.IsSuccessStatusCode ? LogLevel.Critical : LogLevel.Debug,
|
||||
$"{requestShockers.RequestUri} response: {response.StatusCode}\n{shockerJson}");
|
||||
JObject shockerListJObj = JObject.Parse(shockerJson);
|
||||
shockerIds.AddRange(shockerListJObj["data"]!.Children()["id"].Values<string>()!);
|
||||
|
||||
}
|
||||
return shockerIds;
|
||||
}
|
||||
|
||||
protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration)
|
||||
{
|
||||
HttpRequestMessage request = new (HttpMethod.Post, $"{Endpoint}/2/shockers/control")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
|
||||
},
|
||||
Content = new StringContent("{" +
|
||||
"\"shocks\": ["+
|
||||
"{"+
|
||||
$"\"id\": \"{shockerId}\"," +
|
||||
$"\"type\": {ControlActionToByte(action)},"+
|
||||
$"\"intensity\": {intensity},"+
|
||||
$"\"duration\": {duration}"+
|
||||
"}" +
|
||||
"]," +
|
||||
"\"customName\": CShocker" +
|
||||
"}", Encoding.UTF8, new MediaTypeHeaderValue("application/json"))
|
||||
};
|
||||
request.Headers.Add("OpenShockToken", ApiKey);
|
||||
this.Logger?.Log(LogLevel.Debug, $"Request-Content: {request.Content}");
|
||||
HttpResponseMessage response = HttpClient.Send(request);
|
||||
this.Logger?.Log(!response.IsSuccessStatusCode ? LogLevel.Critical : 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
|
||||
};
|
||||
}
|
||||
|
||||
public OpenShockHttp(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, string apiKey, string endpoint = "https://api.shocklink.net", ILogger? logger = null) : base(shockerIds, intensityRange, durationRange, apiKey, endpoint, ShockerApi.OpenShockHttp, logger)
|
||||
{
|
||||
}
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
using System.Net.Http.Headers;
|
||||
using CShocker.Ranges;
|
||||
using CShocker.Shockers.Abstract;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CShocker.Shockers.APIS;
|
||||
|
||||
public class OpenShockSerial : SerialShocker
|
||||
{
|
||||
// ReSharper disable once MemberCanBePrivate.Global external usage
|
||||
public readonly Dictionary<string, ShockerModel> Model;
|
||||
private const int BaudRate = 115200;
|
||||
public OpenShockSerial(Dictionary<string, ShockerModel> shockerIds, IntensityRange intensityRange, DurationRange durationRange, SerialPortInfo serialPortI, ILogger? logger = null) : base(shockerIds.Keys.ToList(), intensityRange, durationRange, serialPortI, BaudRate, ShockerApi.OpenShockSerial, logger)
|
||||
{
|
||||
this.Model = shockerIds;
|
||||
}
|
||||
|
||||
protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration)
|
||||
{
|
||||
string json = "rftransmit {" +
|
||||
$"\"model\":\"{Enum.GetName(Model[shockerId])!.ToLower()}\"," +
|
||||
$"\"id\":{shockerId}," +
|
||||
$"\"type\":\"{ControlActionToString(action)}\"," +
|
||||
$"\"intensity\":{intensity}," +
|
||||
$"\"durationMs\":{duration}" +
|
||||
"}";
|
||||
SerialPort.WriteLine(json);
|
||||
}
|
||||
|
||||
public Dictionary<string, ShockerModel> GetShockers(string apiEndpoint, string apiKey)
|
||||
{
|
||||
HttpClient httpClient = new();
|
||||
HttpRequestMessage requestDevices = new (HttpMethod.Get, $"{apiEndpoint}/2/devices")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
|
||||
}
|
||||
};
|
||||
requestDevices.Headers.Add("OpenShockToken", apiKey);
|
||||
HttpResponseMessage responseDevices = httpClient.Send(requestDevices);
|
||||
|
||||
StreamReader deviceStreamReader = new(responseDevices.Content.ReadAsStream());
|
||||
string deviceJson = deviceStreamReader.ReadToEnd();
|
||||
this.Logger?.Log(LogLevel.Debug, $"{requestDevices.RequestUri} response: {responseDevices.StatusCode}\n{deviceJson}");
|
||||
JObject deviceListJObj = JObject.Parse(deviceJson);
|
||||
List<string> deviceIds = new();
|
||||
deviceIds.AddRange(deviceListJObj["data"]!.Children()["id"].Values<string>()!);
|
||||
|
||||
Dictionary<string, ShockerModel> models = new();
|
||||
foreach (string deviceId in deviceIds)
|
||||
{
|
||||
HttpRequestMessage requestShockers = new (HttpMethod.Get, $"{apiEndpoint}/2/devices/{deviceId}/shockers")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("application/json") }
|
||||
}
|
||||
};
|
||||
requestShockers.Headers.Add("OpenShockToken", apiKey);
|
||||
HttpResponseMessage response = httpClient.Send(requestShockers);
|
||||
|
||||
StreamReader shockerStreamReader = new(response.Content.ReadAsStream());
|
||||
string shockerJson = shockerStreamReader.ReadToEnd();
|
||||
this.Logger?.Log(LogLevel.Debug, $"{requestShockers.RequestUri} response: {response.StatusCode}\n{shockerJson}");
|
||||
JObject shockerListJObj = JObject.Parse(shockerJson);
|
||||
for (int i = 0; i < shockerListJObj["data"]!.Children().Count(); i++)
|
||||
{
|
||||
models.Add(
|
||||
shockerListJObj["data"]![i]!["rfId"]!.Value<int>().ToString(),
|
||||
Enum.Parse<ShockerModel>(shockerListJObj["data"]![i]!["model"]!.Value<string>()!)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return models;
|
||||
}
|
||||
|
||||
public enum ShockerModel : byte
|
||||
{
|
||||
CaiXianlin = 0,
|
||||
Petrainer = 1
|
||||
}
|
||||
|
||||
private static string ControlActionToString(ControlAction action)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
ControlAction.Beep => "sound",
|
||||
ControlAction.Vibrate => "vibrate",
|
||||
ControlAction.Shock => "shock",
|
||||
_ => "stop"
|
||||
};
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using CShocker.Ranges;
|
||||
using CShocker.Shockers.Abstract;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CShocker.Shockers.APIS;
|
||||
|
||||
public class PiShockHttp : HttpShocker
|
||||
{
|
||||
// ReSharper disable twice MemberCanBePrivate.Global external usage
|
||||
public readonly string Username, ShareCode;
|
||||
|
||||
public PiShockHttp(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, string apiKey, string username, string shareCode, string endpoint = "https://do.pishock.com/api/apioperate", ILogger? logger = null) : base(shockerIds, intensityRange, durationRange, apiKey, endpoint, ShockerApi.PiShockHttp, logger)
|
||||
{
|
||||
this.Username = username;
|
||||
this.ShareCode = shareCode;
|
||||
}
|
||||
|
||||
protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration)
|
||||
{
|
||||
HttpRequestMessage request = new (HttpMethod.Post, $"{Endpoint}")
|
||||
{
|
||||
Headers =
|
||||
{
|
||||
UserAgent = { new ProductInfoHeaderValue("CShocker", "1") },
|
||||
Accept = { new MediaTypeWithQualityHeaderValue("text/plain") }
|
||||
},
|
||||
Content = new StringContent("{" +
|
||||
$"\"Username\":\"{Username}\"," +
|
||||
"\"Name\":\"CShocker\"," +
|
||||
$"\"Code\":\"{ShareCode}\"," +
|
||||
$"\"Intensity\":\"{intensity}\"," +
|
||||
$"\"Duration\":\"{duration/1000}\"," + //duration is in seconds no ms
|
||||
$"\"Apikey\":\"{ApiKey}\"," +
|
||||
$"\"Op\":\"{ControlActionToByte(action)}\"" +
|
||||
"}", Encoding.UTF8, new MediaTypeHeaderValue("application/json"))
|
||||
};
|
||||
HttpResponseMessage response = HttpClient.Send(request);
|
||||
this.Logger?.Log(LogLevel.Debug, $"{request.RequestUri} response: {response.StatusCode} {response.Content.ReadAsStringAsync()}");
|
||||
}
|
||||
|
||||
private byte ControlActionToByte(ControlAction action)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
ControlAction.Beep => 2,
|
||||
ControlAction.Vibrate => 1,
|
||||
ControlAction.Shock => 0,
|
||||
_ => 2
|
||||
};
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
using CShocker.Ranges;
|
||||
using CShocker.Shockers.Abstract;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CShocker.Shockers.APIS;
|
||||
|
||||
public class PiShockSerial : SerialShocker
|
||||
{
|
||||
private const int BaudRate = 115200;
|
||||
public PiShockSerial(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, SerialPortInfo serialPortI, ILogger? logger = null) : base(shockerIds, intensityRange, durationRange, serialPortI, BaudRate, ShockerApi.PiShockSerial, logger)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void ControlInternal(ControlAction action, string shockerId, int intensity, int duration)
|
||||
{
|
||||
string json = "{" +
|
||||
"\"cmd\": \"operate\"," +
|
||||
"\"value\":{" +
|
||||
$"\"op\": \"{ControlActionToOp(action)}\"," +
|
||||
$"\"duration\": {duration}," +
|
||||
$"\"intensity\": {intensity}," +
|
||||
$"\"id\": " +
|
||||
"}" +
|
||||
"}";
|
||||
SerialPort.WriteLine(json);
|
||||
}
|
||||
|
||||
private static string ControlActionToOp(ControlAction action)
|
||||
{
|
||||
return action switch
|
||||
{
|
||||
ControlAction.Beep => "",
|
||||
ControlAction.Vibrate => "vibrate",
|
||||
ControlAction.Shock => "",
|
||||
_ => ""
|
||||
};
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
using CShocker.Ranges;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace CShocker.Shockers.Abstract;
|
||||
|
||||
public abstract class HttpShocker : Shocker
|
||||
{
|
||||
protected readonly HttpClient HttpClient = new();
|
||||
// ReSharper disable twice MemberCanBeProtected.Global external usage
|
||||
public string Endpoint { get; init; }
|
||||
public string ApiKey { get; init; }
|
||||
|
||||
protected HttpShocker(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, string apiKey, string endpoint, ShockerApi apiType, ILogger? logger = null) : base(shockerIds, intensityRange, durationRange, apiType, logger)
|
||||
{
|
||||
Endpoint = endpoint;
|
||||
ApiKey = apiKey;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{base.ToString()}\n" +
|
||||
$"Endpoint: {Endpoint}\n" +
|
||||
$"ApiKey: {ApiKey}";
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
using System.IO.Ports;
|
||||
using CShocker.Ranges;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Management;
|
||||
using System.Runtime.Versioning;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace CShocker.Shockers.Abstract;
|
||||
|
||||
public abstract class SerialShocker : Shocker
|
||||
{
|
||||
public SerialPortInfo SerialPortI;
|
||||
protected readonly SerialPort SerialPort;
|
||||
|
||||
protected SerialShocker(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, SerialPortInfo serialPortI, int baudRate, ShockerApi apiType, ILogger? logger = null) : base(shockerIds, intensityRange, durationRange, apiType, logger)
|
||||
{
|
||||
this.SerialPortI = serialPortI;
|
||||
this.SerialPort = new SerialPort(serialPortI.PortName, baudRate);
|
||||
this.SerialPort.Open();
|
||||
}
|
||||
|
||||
[SupportedOSPlatform("windows")]
|
||||
public static List<SerialPortInfo> GetSerialPorts()
|
||||
{
|
||||
List<SerialPortInfo> ret = new();
|
||||
using (ManagementClass entity = new("Win32_PnPEntity"))
|
||||
{
|
||||
// ReSharper disable once InconsistentNaming
|
||||
const string CUR_CTRL = "HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\";
|
||||
|
||||
foreach (ManagementObject instance in entity.GetInstances())
|
||||
{
|
||||
object oGuid;
|
||||
oGuid = instance.GetPropertyValue("ClassGuid");
|
||||
if (oGuid == null || oGuid.ToString()?.ToUpper().Equals("{4D36E978-E325-11CE-BFC1-08002BE10318}") is false)
|
||||
continue; // Skip all devices except device class "PORTS"
|
||||
|
||||
string? caption = instance.GetPropertyValue("Caption")?.ToString();
|
||||
string? manufacturer = instance.GetPropertyValue("Manufacturer")?.ToString();
|
||||
string? deviceID = instance.GetPropertyValue("PnpDeviceID")?.ToString();
|
||||
string regEnum = CUR_CTRL + "Enum\\" + deviceID + "\\Device Parameters";
|
||||
string? portName = Registry.GetValue(regEnum, "PortName", "")?.ToString();
|
||||
|
||||
int? s32Pos = caption?.IndexOf(" (COM");
|
||||
if (s32Pos > 0) // remove COM port from description
|
||||
caption = caption?.Substring(0, (int)s32Pos);
|
||||
|
||||
ret.Add(new SerialPortInfo(
|
||||
portName,
|
||||
caption,
|
||||
manufacturer,
|
||||
deviceID));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public class SerialPortInfo
|
||||
{
|
||||
public readonly string? PortName, Description, Manufacturer, DeviceID;
|
||||
|
||||
public SerialPortInfo(string? portName, string? description, string? manufacturer, string? deviceID)
|
||||
{
|
||||
this.PortName = portName;
|
||||
this.Description = description;
|
||||
this.Manufacturer = manufacturer;
|
||||
this.DeviceID = deviceID;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return
|
||||
$"PortName: {PortName}\nDescription: {Description}\nManufacturer: {Manufacturer}\nDeviceID: {DeviceID}";
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +1,5 @@
|
||||
using System.Reflection.Metadata;
|
||||
using CShocker.Ranges;
|
||||
using Microsoft.Extensions.Logging;
|
||||
namespace CShocker.Shockers.Abstract;
|
||||
|
||||
namespace CShocker.Shockers.Abstract;
|
||||
|
||||
public abstract class Shocker
|
||||
public interface IShocker
|
||||
{
|
||||
// ReSharper disable 4 times MemberCanBePrivate.Global external use
|
||||
public readonly List<string> ShockerIds;
|
||||
public readonly IntensityRange IntensityRange;
|
||||
public readonly DurationRange DurationRange;
|
||||
protected ILogger? Logger;
|
||||
public readonly ShockerApi ApiType;
|
||||
|
||||
public void Control(ControlAction action, string? shockerId = null, int? intensity = null, int? duration = null)
|
||||
{
|
||||
int i = intensity ?? IntensityRange.GetRandomRangeValue();
|
||||
int d = duration ?? DurationRange.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 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(List<string> shockerIds, IntensityRange intensityRange, DurationRange durationRange, ShockerApi apiType, ILogger? logger = null)
|
||||
{
|
||||
this.ShockerIds = shockerIds;
|
||||
this.IntensityRange = intensityRange;
|
||||
this.DurationRange = durationRange;
|
||||
this.ApiType = apiType;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public void SetLogger(ILogger? logger)
|
||||
{
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"ShockerType: {Enum.GetName(typeof(ShockerApi), this.ApiType)}\n" +
|
||||
$"Shocker-IDs: {string.Join(", ", this.ShockerIds)}\n" +
|
||||
$"IntensityRange: {IntensityRange}\n" +
|
||||
$"DurationRange: {DurationRange}";
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace CShocker.Shockers.Abstract;
|
||||
|
||||
public enum ShockerApi : byte
|
||||
{
|
||||
OpenShockHttp = 0,
|
||||
OpenShockSerial = 1,
|
||||
PiShockHttp = 2,
|
||||
PiShockSerial = 3
|
||||
}
|
48
CShocker/Shockers/Additional/ShockerJsonConverter.cs
Normal file
48
CShocker/Shockers/Additional/ShockerJsonConverter.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using CShocker.Shockers.Abstract;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CShocker.Shockers.Additional;
|
||||
|
||||
public class ShockerJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(IShocker));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject jo = JObject.Load(reader);
|
||||
if (jo.ContainsKey("model")) //OpenShockShocker
|
||||
{
|
||||
return new OpenShockShocker()
|
||||
{
|
||||
name = jo.SelectToken("name")!.Value<string>()!,
|
||||
id = jo.SelectToken("id")!.Value<string>()!,
|
||||
rfId = jo.SelectToken("rfId")!.Value<short>(),
|
||||
model = (OpenShockShocker.OpenShockModel)jo.SelectToken("model")!.Value<byte>(),
|
||||
createdOn = jo.SelectToken("createdOn")!.Value<DateTime>(),
|
||||
isPaused = jo.SelectToken("isPaused")!.Value<bool>()
|
||||
};
|
||||
}
|
||||
else //PiShockShocker
|
||||
{
|
||||
return new PiShockShocker()
|
||||
{
|
||||
Code = jo.SelectToken("Code")!.Value<string>()!
|
||||
};
|
||||
}
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
/// <summary>
|
||||
/// Don't call this
|
||||
/// </summary>
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
throw new Exception("Dont call this");
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace CShocker.Shockers;
|
||||
|
||||
public enum ControlAction
|
||||
{
|
||||
Beep,
|
||||
Vibrate,
|
||||
Shock,
|
||||
Nothing
|
||||
}
|
32
CShocker/Shockers/OpenShockShocker.cs
Normal file
32
CShocker/Shockers/OpenShockShocker.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using CShocker.Shockers.Abstract;
|
||||
|
||||
namespace CShocker.Shockers;
|
||||
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public struct OpenShockShocker : IShocker
|
||||
{
|
||||
public string name, id;
|
||||
public short rfId;
|
||||
public OpenShockModel model;
|
||||
public DateTime createdOn;
|
||||
public bool isPaused;
|
||||
|
||||
public enum OpenShockModel : byte
|
||||
{
|
||||
CaiXianlin = 0,
|
||||
Petrainer = 1
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{GetType().Name}\n" +
|
||||
$"Name: {name}\n" +
|
||||
$"ID: {id}\n" +
|
||||
$"RF-ID: {rfId}\n" +
|
||||
$"Model: {Enum.GetName(model)}\n" +
|
||||
$"Created On: {createdOn}\n" +
|
||||
$"Paused: {isPaused}\n\r";
|
||||
}
|
||||
}
|
8
CShocker/Shockers/PiShockShocker.cs
Normal file
8
CShocker/Shockers/PiShockShocker.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using CShocker.Shockers.Abstract;
|
||||
|
||||
namespace CShocker.Shockers;
|
||||
|
||||
public struct PiShockShocker : IShocker
|
||||
{
|
||||
public string Code;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
using CShocker.Ranges;
|
||||
using CShocker.Shockers.Abstract;
|
||||
using CShocker.Shockers.APIS;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace CShocker.Shockers;
|
||||
|
||||
public class ShockerJsonConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return (objectType == typeof(Shocker));
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
||||
{
|
||||
JObject jo = JObject.Load(reader);
|
||||
ShockerApi? apiType = (ShockerApi?)jo.SelectToken("ApiType")?.Value<byte>();
|
||||
|
||||
switch (apiType)
|
||||
{
|
||||
case ShockerApi.OpenShockHttp:
|
||||
return new OpenShockHttp(
|
||||
jo.SelectToken("ShockerIds")!.ToObject<List<string>>()!,
|
||||
jo.SelectToken("IntensityRange")!.ToObject<IntensityRange>()!,
|
||||
jo.SelectToken("DurationRange")!.ToObject<DurationRange>()!,
|
||||
jo.SelectToken("ApiKey")!.Value<string>()!,
|
||||
jo.SelectToken("Endpoint")!.Value<string>()!
|
||||
);
|
||||
case ShockerApi.OpenShockSerial:
|
||||
return new OpenShockSerial(
|
||||
jo.SelectToken("Model")!.ToObject<Dictionary<string, OpenShockSerial.ShockerModel>>()!,
|
||||
jo.SelectToken("IntensityRange")!.ToObject<IntensityRange>()!,
|
||||
jo.SelectToken("DurationRange")!.ToObject<DurationRange>()!,
|
||||
jo.SelectToken("SerialPortI")!.ToObject<SerialShocker.SerialPortInfo>()!
|
||||
);
|
||||
case ShockerApi.PiShockHttp:
|
||||
return new PiShockHttp(
|
||||
jo.SelectToken("ShockerIds")!.ToObject<List<string>>()!,
|
||||
jo.SelectToken("IntensityRange")!.ToObject<IntensityRange>()!,
|
||||
jo.SelectToken("DurationRange")!.ToObject<DurationRange>()!,
|
||||
jo.SelectToken("ApiKey")!.Value<string>()!,
|
||||
jo.SelectToken("Username")!.Value<string>()!,
|
||||
jo.SelectToken("ShareCode")!.Value<string>()!,
|
||||
jo.SelectToken("Endpoint")!.Value<string>()!
|
||||
);
|
||||
case ShockerApi.PiShockSerial:
|
||||
throw new NotImplementedException();
|
||||
default:
|
||||
throw new Exception();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanWrite => false;
|
||||
|
||||
/// <summary>
|
||||
/// Don't call this
|
||||
/// </summary>
|
||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
||||
{
|
||||
throw new Exception("Dont call this");
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user