File tree 6 files changed +586
-285
lines changed
NexusMods.CLI/Types/IpcHandlers
NexusMods.DataModel/Interprocess
tests/NexusMods.DataModel.Tests
6 files changed +586
-285
lines changed Original file line number Diff line number Diff line change @@ -13,7 +13,7 @@ public class NxmIpcProtocolHandler : IIpcProtocolHandler
13
13
/// <inheritdoc/>
14
14
public string Protocol => "nxm" ;
15
15
16
- private IMessageProducer < NXMUrlMessage > _messages ;
16
+ private readonly IMessageProducer < NXMUrlMessage > _messages ;
17
17
18
18
/// <summary>
19
19
/// constructor
@@ -27,6 +27,7 @@ public NxmIpcProtocolHandler(IMessageProducer<NXMUrlMessage> messages)
27
27
public async Task Handle ( string url , CancellationToken cancel )
28
28
{
29
29
await _messages . Write ( new NXMUrlMessage { Value = NXMUrl . Parse ( url ) } , cancel ) ;
30
+ _messages . EnsureWrite ( cancel ) ;
30
31
}
31
32
}
32
33
Original file line number Diff line number Diff line change @@ -4,12 +4,19 @@ namespace NexusMods.DataModel.Interprocess;
4
4
/// A message producer for sending messages to other processes.
5
5
/// </summary>
6
6
/// <typeparam name="T">Message type to send, each message type gets its own queue</typeparam>
7
- public interface IMessageProducer < T > where T : IMessage
7
+ public interface IMessageProducer < in T > where T : IMessage
8
8
{
9
9
/// <summary>
10
10
/// Sends a message to the queue.
11
11
/// </summary>
12
12
/// <param name="message">The message to write.</param>
13
13
/// <param name="token">Can be used to cancel this operation.</param>
14
14
public ValueTask Write ( T message , CancellationToken token ) ;
15
+
16
+ /// <summary>
17
+ /// Ensures all messages in-flight have been saved to the database.
18
+ /// This is done using an <see cref="EventWaitHandle"/> and this call
19
+ /// will block the entire thread.
20
+ /// </summary>
21
+ public void EnsureWrite ( CancellationToken cancellationToken ) ;
15
22
}
Original file line number Diff line number Diff line change
1
+ using System . Diagnostics ;
2
+ using System . Reactive . Linq ;
3
+
1
4
namespace NexusMods . DataModel . Interprocess ;
2
5
3
6
/// <summary>
@@ -48,4 +51,21 @@ private void WriteInner(T message)
48
51
var used = message . Write ( buffer ) ;
49
52
_sqliteIpc . Send ( _queueName , buffer [ ..used ] ) ;
50
53
}
54
+
55
+ /// <inheritdoc/>
56
+ public void EnsureWrite ( CancellationToken cancellationToken )
57
+ {
58
+ var timeout = SqliteIPC . WriterLoopInterval + SqliteIPC . SqliteDefaultTimeout ;
59
+ Thread . Sleep ( timeout ) ;
60
+
61
+ const int maxIterations = 10 ;
62
+ var i = 0 ;
63
+
64
+ while ( i < maxIterations && ! cancellationToken . IsCancellationRequested )
65
+ {
66
+ var signaled = _sqliteIpc . WriterLoopFinished . WaitOne ( timeout ) ;
67
+ if ( signaled ) break ;
68
+ i += 1 ;
69
+ }
70
+ }
51
71
}
Original file line number Diff line number Diff line change
1
+ namespace NexusMods . DataModel . Interprocess ;
2
+
3
+ internal readonly struct SemaphoreSlimWaiter : IDisposable
4
+ {
5
+ private readonly SemaphoreSlim _semaphoreSlim ;
6
+
7
+ public bool HasEntered { get ; }
8
+
9
+ internal SemaphoreSlimWaiter ( SemaphoreSlim semaphoreSlim , bool entered )
10
+ {
11
+ _semaphoreSlim = semaphoreSlim ;
12
+ HasEntered = entered ;
13
+ }
14
+
15
+ public void Dispose ( )
16
+ {
17
+ if ( ! HasEntered ) return ;
18
+ _semaphoreSlim . Release ( ) ;
19
+ }
20
+ }
21
+
22
+ internal static class SemaphoreExtensions
23
+ {
24
+ public static SemaphoreSlimWaiter CustomWait (
25
+ this SemaphoreSlim semaphoreSlim ,
26
+ TimeSpan timeout ,
27
+ CancellationToken cancellationToken = default )
28
+ {
29
+ var entered = semaphoreSlim . Wait ( timeout , cancellationToken ) ;
30
+ return new SemaphoreSlimWaiter ( semaphoreSlim , entered ) ;
31
+ }
32
+ }
You can’t perform that action at this time.
0 commit comments