mirror of
https://github.com/evopro-ag/Sharp7Reactive.git
synced 2025-12-16 11:42:52 +00:00
fixed value notifications
added observable extensions
This commit is contained in:
@@ -1,24 +1,114 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Linq.Expressions;
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
|
using System.Reactive.Concurrency;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using System.Reactive.Linq;
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using Sharp7.Rx.Resources;
|
||||||
|
|
||||||
namespace Sharp7.Rx.Extensions
|
namespace Sharp7.Rx.Extensions
|
||||||
{
|
{
|
||||||
internal static class ObservableExtensions
|
internal static class ObservableExtensions
|
||||||
{
|
{
|
||||||
public static IObservable<Unit> Select<TSource>(this IObservable<TSource> source, Func<TSource, Task> selector)
|
public static IObservable<Unit> Select<TSource>(this IObservable<TSource> source, Func<TSource, Task> selector)
|
||||||
{
|
{
|
||||||
return source
|
return source
|
||||||
.Select(x => Observable.FromAsync(async () => await selector(x)))
|
.Select(x => Observable.FromAsync(async () => await selector(x)))
|
||||||
.Concat();
|
.Concat();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IObservable<TResult> Select<TSource, TResult>(this IObservable<TSource> source, Func<TSource, Task<TResult>> selector)
|
public static IObservable<TResult> Select<TSource, TResult>(this IObservable<TSource> source, Func<TSource, Task<TResult>> selector)
|
||||||
{
|
{
|
||||||
return source
|
return source
|
||||||
.Select(x => Observable.FromAsync(async () => await selector(x)))
|
.Select(x => Observable.FromAsync(async () => await selector(x)))
|
||||||
.Concat();
|
.Concat();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
public static IObservable<T> LogAndRetry<T>(this IObservable<T> source, ILogger logger, string message)
|
||||||
|
{
|
||||||
|
return source
|
||||||
|
.Do(
|
||||||
|
_ => { },
|
||||||
|
ex => logger?.LogError(ex, message))
|
||||||
|
.Retry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObservable<T> RetryAfterDelay<T>(
|
||||||
|
this IObservable<T> source,
|
||||||
|
TimeSpan retryDelay,
|
||||||
|
int retryCount = -1,
|
||||||
|
IScheduler scheduler = null)
|
||||||
|
{
|
||||||
|
return RedoAfterDelay(source, retryDelay, retryCount, scheduler, Observable.Retry, Observable.Retry);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObservable<T> RepeatAfterDelay<T>(
|
||||||
|
this IObservable<T> source,
|
||||||
|
TimeSpan retryDelay,
|
||||||
|
int repeatCount = -1,
|
||||||
|
IScheduler scheduler = null)
|
||||||
|
{
|
||||||
|
return RedoAfterDelay(source, retryDelay, repeatCount, scheduler, Observable.Repeat, Observable.Repeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObservable<T> LogAndRetryAfterDelay<T>(
|
||||||
|
this IObservable<T> source,
|
||||||
|
ILogger logger,
|
||||||
|
TimeSpan retryDelay,
|
||||||
|
string message,
|
||||||
|
int retryCount = -1,
|
||||||
|
IScheduler scheduler = null)
|
||||||
|
{
|
||||||
|
var sourceLogged =
|
||||||
|
source
|
||||||
|
.Do(
|
||||||
|
_ => { },
|
||||||
|
ex => logger?.LogError(ex, message));
|
||||||
|
|
||||||
|
return RetryAfterDelay(sourceLogged, retryDelay, retryCount, scheduler);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IObservable<T> RedoAfterDelay<T>(IObservable<T> source, TimeSpan retryDelay, int retryCount, IScheduler scheduler, Func<IObservable<T>, IObservable<T>> reDo,
|
||||||
|
Func<IObservable<T>, int, IObservable<T>> reDoCount)
|
||||||
|
{
|
||||||
|
scheduler = scheduler ?? TaskPoolScheduler.Default;
|
||||||
|
var attempt = 0;
|
||||||
|
|
||||||
|
var deferedObs = Observable.Defer(() => ((++attempt == 1) ? source : source.DelaySubscription(retryDelay, scheduler)));
|
||||||
|
return retryCount > 0 ? reDoCount(deferedObs, retryCount) : reDo(deferedObs);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObservable<T> DisposeMany<T>(this IObservable<T> source)
|
||||||
|
{
|
||||||
|
return Observable.Create<T>(obs =>
|
||||||
|
{
|
||||||
|
var serialDisposable = new SerialDisposable();
|
||||||
|
var subscription =
|
||||||
|
source.Subscribe(
|
||||||
|
item =>
|
||||||
|
{
|
||||||
|
serialDisposable.Disposable = item as IDisposable;
|
||||||
|
obs.OnNext(item);
|
||||||
|
},
|
||||||
|
obs.OnError,
|
||||||
|
obs.OnCompleted);
|
||||||
|
return new CompositeDisposable(serialDisposable, subscription);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IObservable<Unit> SelectMany<T>(this IObservable<T> source, Func<T, Task> selector)
|
||||||
|
{
|
||||||
|
return source.SelectMany(async item =>
|
||||||
|
{
|
||||||
|
await selector(item);
|
||||||
|
return Unit.Default;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,5 +9,6 @@ namespace Sharp7.Rx.Interfaces
|
|||||||
IObservable<TValue> CreateNotification<TValue>(string variableName, TransmissionMode transmissionMode, TimeSpan cycleSpan);
|
IObservable<TValue> CreateNotification<TValue>(string variableName, TransmissionMode transmissionMode, TimeSpan cycleSpan);
|
||||||
Task SetValue<TValue>(string variableName, TValue value);
|
Task SetValue<TValue>(string variableName, TValue value);
|
||||||
Task<TValue> GetValue<TValue>(string variableName);
|
Task<TValue> GetValue<TValue>(string variableName);
|
||||||
|
IObservable<ConnectionState> ConnectionState { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Sharp7.Rx.Enums;
|
using Sharp7.Rx.Enums;
|
||||||
|
|
||||||
namespace Sharp7.Rx.Interfaces
|
namespace Sharp7.Rx.Interfaces
|
||||||
@@ -18,5 +19,6 @@ namespace Sharp7.Rx.Interfaces
|
|||||||
|
|
||||||
Task<bool> WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNr, CancellationToken token);
|
Task<bool> WriteBit(Operand operand, ushort startByteAddress, byte bitAdress, bool value, ushort dbNr, CancellationToken token);
|
||||||
Task<ushort> WriteBytes(Operand operand, ushort startByteAdress, byte[] data, ushort dBNr, CancellationToken token);
|
Task<ushort> WriteBytes(Operand operand, ushort startByteAdress, byte[] data, ushort dBNr, CancellationToken token);
|
||||||
|
ILogger Logger { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
|
||||||
<PackageReference Include="Sharp7" Version="1.0.18" />
|
<PackageReference Include="Sharp7" Version="1.0.18" />
|
||||||
<PackageReference Include="System.Reactive" Version="4.1.0" />
|
<PackageReference Include="System.Reactive" Version="4.1.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ using System.Reactive.Linq;
|
|||||||
using System.Reactive.Subjects;
|
using System.Reactive.Subjects;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Sharp7.Rx.Enums;
|
using Sharp7.Rx.Enums;
|
||||||
|
using Sharp7.Rx.Extensions;
|
||||||
using Sharp7.Rx.Interfaces;
|
using Sharp7.Rx.Interfaces;
|
||||||
using Sharp7.Rx.Resources;
|
using Sharp7.Rx.Resources;
|
||||||
|
|
||||||
@@ -18,17 +20,21 @@ namespace Sharp7.Rx
|
|||||||
private readonly string ipAddress;
|
private readonly string ipAddress;
|
||||||
private readonly int rackNr;
|
private readonly int rackNr;
|
||||||
private readonly int cpuSlotNr;
|
private readonly int cpuSlotNr;
|
||||||
|
private readonly int port;
|
||||||
|
|
||||||
private S7Client sharp7;
|
private S7Client sharp7;
|
||||||
private bool disposed;
|
private bool disposed;
|
||||||
|
|
||||||
public Sharp7Connector(string ipAddress, int rackNr = 0, int cpuSlotNr = 2)
|
public ILogger Logger { get; set; }
|
||||||
{
|
|
||||||
|
public Sharp7Connector(string ipAddress, int rackNr = 0, int cpuSlotNr = 2, int port = 102)
|
||||||
|
{
|
||||||
this.ipAddress = ipAddress;
|
this.ipAddress = ipAddress;
|
||||||
this.cpuSlotNr = cpuSlotNr;
|
this.cpuSlotNr = cpuSlotNr;
|
||||||
this.rackNr = rackNr;
|
this.port = port;
|
||||||
|
this.rackNr = rackNr;
|
||||||
|
|
||||||
ReconnectDelay = TimeSpan.FromSeconds(5);
|
ReconnectDelay = TimeSpan.FromSeconds(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan ReconnectDelay { get; set; }
|
public TimeSpan ReconnectDelay { get; set; }
|
||||||
@@ -76,22 +82,23 @@ namespace Sharp7.Rx
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
sharp7 = new S7Client();
|
sharp7 = new S7Client();
|
||||||
|
sharp7.PLCPort = this.port;
|
||||||
|
|
||||||
var subscription =
|
var subscription =
|
||||||
ConnectionState
|
ConnectionState
|
||||||
.Where(state => state == Enums.ConnectionState.ConnectionLost)
|
.Where(state => state == Enums.ConnectionState.ConnectionLost)
|
||||||
.Take(1)
|
.Take(1)
|
||||||
.SelectMany(_ => Reconnect())
|
.SelectMany(_ => Reconnect())
|
||||||
// TODO: .RepeatAfterDelay(ReconnectDelay)
|
.RepeatAfterDelay(ReconnectDelay)
|
||||||
// TODO: .LogAndRetry(logger, "Error while reconnecting to S7.")
|
.LogAndRetry(Logger, "Error while reconnecting to S7.")
|
||||||
.Subscribe();
|
.Subscribe();
|
||||||
|
|
||||||
disposables.Add(subscription);
|
disposables.Add(subscription);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
// TODO:
|
Logger?.LogError(ex, StringResources.StrErrorS7DriverCouldNotBeInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.FromResult(true);
|
return Task.FromResult(true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ using System.Reactive.Subjects;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
using Sharp7.Rx.Enums;
|
using Sharp7.Rx.Enums;
|
||||||
|
using Sharp7.Rx.Extensions;
|
||||||
using Sharp7.Rx.Interfaces;
|
using Sharp7.Rx.Interfaces;
|
||||||
using Sharp7.Rx.Resources;
|
using Sharp7.Rx.Resources;
|
||||||
|
|
||||||
@@ -247,8 +249,8 @@ namespace Sharp7.Rx
|
|||||||
Value = value
|
Value = value
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
// TODO: .RepeatAfterDelay(cycle)
|
.RepeatAfterDelay(cycle)
|
||||||
// TODO: .LogAndRetryAfterDelay(Logger, cycle, StringResources.StrLogErrorReadingDataFromPlc)
|
.LogAndRetryAfterDelay(s7Connector.Logger, cycle, StringResources.StrLogErrorReadingDataFromPlc)
|
||||||
.TakeUntil(disposingSubject)
|
.TakeUntil(disposingSubject)
|
||||||
.Where(union => union.HasValue)
|
.Where(union => union.HasValue)
|
||||||
.Select(union => union.Value);
|
.Select(union => union.Value);
|
||||||
|
|||||||
Reference in New Issue
Block a user