|
1 | 1 | // ReSharper disable ParameterTypeCanBeEnumerable.Local
|
2 | 2 | // ReSharper disable CheckNamespace
|
| 3 | +using System.Reflection; |
| 4 | +using System.Text.Json.Nodes; |
| 5 | + |
3 | 6 | namespace Atc.Kepware.Configuration.Services;
|
4 | 7 |
|
5 | 8 | /// <summary>
|
@@ -206,6 +209,67 @@ public async Task<HttpClientRequestResult<bool>> IsTagGroupDefined(
|
206 | 209 | return response.Adapt<HttpClientRequestResult<IList<DeviceBase>?>>();
|
207 | 210 | }
|
208 | 211 |
|
| 212 | + public async Task<HttpClientRequestResult<IList<TDevice>?>> GetDevicesByChannelName<TDevice>( |
| 213 | + string channelName, |
| 214 | + CancellationToken cancellationToken) |
| 215 | + where TDevice : DeviceBase |
| 216 | + { |
| 217 | + ArgumentNullException.ThrowIfNull(channelName); |
| 218 | + |
| 219 | + if (!IsValidConnectivityName( |
| 220 | + channelName, |
| 221 | + deviceName: null, |
| 222 | + tagGroupNameOrTagName: null, |
| 223 | + tagGroupStructure: null, |
| 224 | + out var errorMessage)) |
| 225 | + { |
| 226 | + return await Task.FromResult(HttpClientRequestResultFactory<IList<TDevice>?>.CreateBadRequest(errorMessage!)); |
| 227 | + } |
| 228 | + |
| 229 | + var response = await Get<IList<JsonObject>>( |
| 230 | + $"{EndpointPathTemplateConstants.Channels}/{channelName}/{EndpointPathTemplateConstants.Devices}", |
| 231 | + cancellationToken); |
| 232 | + |
| 233 | + // TODO: Handle properly and return HttpClientRequestResult<...> |
| 234 | + if (!response.HasData) |
| 235 | + { |
| 236 | + throw new Exception("No data returned!"); |
| 237 | + } |
| 238 | + |
| 239 | + // Get the implemented interfaces that derive from IDeviceBase, but are not IDeviceBase |
| 240 | + // TODO: Cache |
| 241 | + ISet<Type> implementedInterfaces = typeof(TDevice) |
| 242 | + .GetInterfaces() |
| 243 | + .Where(x |
| 244 | + => typeof(IDeviceBase).IsAssignableFrom(x) |
| 245 | + && x != typeof(IDeviceBase)) |
| 246 | + .ToHashSet(); |
| 247 | + |
| 248 | + // Find the first type in this assembly that share an interface |
| 249 | + // TODO: Cache |
| 250 | + Type mappingType = Assembly |
| 251 | + .GetExecutingAssembly() |
| 252 | + .GetTypes() |
| 253 | + .First(x => x |
| 254 | + .GetInterfaces() |
| 255 | + .Any(y => implementedInterfaces.Contains(y))); |
| 256 | + |
| 257 | + // Serialize JSON to internal type and adapt to destination type |
| 258 | + IList<object?> internalDeviceTypes = response |
| 259 | + .Data |
| 260 | + .Select(x => JsonSerializer.Deserialize(x.ToString(), mappingType)) |
| 261 | + .ToList(); |
| 262 | + Type deviceTypeListType = typeof(IList<>).MakeGenericType(typeof(TDevice)); |
| 263 | + IList<TDevice>? deviceTypes = (IList<TDevice>?)internalDeviceTypes.Adapt(typeof(IList<object?>), deviceTypeListType); |
| 264 | + |
| 265 | + return new HttpClientRequestResult<IList<TDevice>?>(deviceTypes) |
| 266 | + { |
| 267 | + CommunicationSucceeded = response.CommunicationSucceeded, |
| 268 | + StatusCode = response.StatusCode, |
| 269 | + Message = response.Message, |
| 270 | + }; |
| 271 | + } |
| 272 | + |
209 | 273 | public async Task<HttpClientRequestResult<TagRoot>> GetTags(
|
210 | 274 | string channelName,
|
211 | 275 | string deviceName,
|
|
0 commit comments