13
13
using Akka . IO ;
14
14
using Akka . Streams . Actors ;
15
15
using Akka . Streams . IO ;
16
- using Akka . Util ;
17
16
18
17
namespace Akka . Streams . Implementation . IO
19
18
{
@@ -35,20 +34,20 @@ internal class FileSubscriber : ActorSubscriber
35
34
/// <exception cref="ArgumentException">TBD</exception>
36
35
/// <returns>TBD</returns>
37
36
public static Props Props (
38
- FileInfo f ,
39
- TaskCompletionSource < IOResult > completionPromise ,
40
- int bufferSize ,
41
- long startPosition ,
37
+ FileInfo f ,
38
+ TaskCompletionSource < IOResult > completionPromise ,
39
+ int bufferSize ,
40
+ long startPosition ,
42
41
FileMode fileMode ,
43
42
bool autoFlush = false ,
44
43
object flushCommand = null )
45
44
{
46
- if ( bufferSize <= 0 )
45
+ if ( bufferSize <= 0 )
47
46
throw new ArgumentException ( $ "bufferSize must be > 0 (was { bufferSize } )", nameof ( bufferSize ) ) ;
48
- if ( startPosition < 0 )
47
+ if ( startPosition < 0 )
49
48
throw new ArgumentException ( $ "startPosition must be >= 0 (was { startPosition } )", nameof ( startPosition ) ) ;
50
49
51
- return Actor . Props . Create ( ( ) => new FileSubscriber ( f , completionPromise , bufferSize , startPosition , fileMode , autoFlush , flushCommand ) )
50
+ return Actor . Props . Create ( ( ) => new FileSubscriber ( f , completionPromise , bufferSize , startPosition , fileMode , autoFlush , flushCommand ) )
52
51
. WithDeploy ( Deploy . Local ) ;
53
52
}
54
53
@@ -74,12 +73,12 @@ public static Props Props(
74
73
/// <param name="autoFlush"></param>
75
74
/// <param name="flushCommand"></param>
76
75
public FileSubscriber (
77
- FileInfo f ,
78
- TaskCompletionSource < IOResult > completionPromise ,
79
- int bufferSize ,
80
- long startPosition ,
76
+ FileInfo f ,
77
+ TaskCompletionSource < IOResult > completionPromise ,
78
+ int bufferSize ,
79
+ long startPosition ,
81
80
FileMode fileMode ,
82
- bool autoFlush ,
81
+ bool autoFlush ,
83
82
object flushCommand )
84
83
{
85
84
_f = f ;
@@ -111,7 +110,7 @@ protected override void PreStart()
111
110
}
112
111
catch ( Exception ex )
113
112
{
114
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
113
+ CloseAndComplete ( IOResult . Failed ( _bytesWritten , ex ) ) ;
115
114
Cancel ( ) ;
116
115
}
117
116
}
@@ -128,32 +127,23 @@ protected override bool Receive(object message)
128
127
case OnNext next :
129
128
try
130
129
{
131
- var byteString = ( ByteString ) next . Element ;
130
+ var byteString = ( ByteString ) next . Element ;
132
131
var bytes = byteString . ToArray ( ) ;
133
- try
134
- {
135
- _chan . Write ( bytes , 0 , bytes . Length ) ;
136
- _bytesWritten += bytes . Length ;
137
- if ( _autoFlush )
138
- _chan . Flush ( true ) ;
139
- }
140
- catch ( Exception ex )
141
- {
142
- _log . Error ( ex , $ "Tearing down FileSink({ _f . FullName } ) due to write error.") ;
143
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
144
- Context . Stop ( Self ) ;
145
- }
132
+ _chan . Write ( bytes , 0 , bytes . Length ) ;
133
+ _bytesWritten += bytes . Length ;
134
+ if ( _autoFlush )
135
+ _chan . Flush ( true ) ;
146
136
}
147
137
catch ( Exception ex )
148
138
{
149
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
139
+ CloseAndComplete ( IOResult . Failed ( _bytesWritten , ex ) ) ;
150
140
Cancel ( ) ;
151
141
}
152
142
return true ;
153
143
154
144
case OnError error :
155
- _log . Error ( error . Cause , $ "Tearing down FileSink({ _f . FullName } ) due to upstream error") ;
156
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , error . Cause ) ) ;
145
+ _log . Error ( error . Cause , "Tearing down FileSink({0 }) due to upstream error" , _f . FullName ) ;
146
+ CloseAndComplete ( IOResult . Failed ( _bytesWritten , error . Cause ) ) ;
157
147
Context . Stop ( Self ) ;
158
148
return true ;
159
149
@@ -164,8 +154,8 @@ protected override bool Receive(object message)
164
154
}
165
155
catch ( Exception ex )
166
156
{
167
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
168
- }
157
+ CloseAndComplete ( IOResult . Failed ( _bytesWritten , ex ) ) ;
158
+ }
169
159
Context . Stop ( Self ) ;
170
160
return true ;
171
161
@@ -176,8 +166,8 @@ protected override bool Receive(object message)
176
166
}
177
167
catch ( Exception ex )
178
168
{
179
- _log . Error ( ex , $ "Tearing down FileSink({ _f . FullName } ). File flush failed.") ;
180
- _completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
169
+ _log . Error ( ex , "Tearing down FileSink({0 }). File flush failed." , _f . FullName ) ;
170
+ CloseAndComplete ( IOResult . Failed ( _bytesWritten , ex ) ) ;
181
171
Context . Stop ( Self ) ;
182
172
}
183
173
return true ;
@@ -190,18 +180,25 @@ protected override bool Receive(object message)
190
180
/// TBD
191
181
/// </summary>
192
182
protected override void PostStop ( )
183
+ {
184
+ CloseAndComplete ( IOResult . Success ( _bytesWritten ) ) ;
185
+ base . PostStop ( ) ;
186
+ }
187
+
188
+ private void CloseAndComplete ( IOResult result )
193
189
{
194
190
try
195
191
{
192
+ // close the channel/file before completing the promise, allowing the
193
+ // file to be deleted, which would not work (on some systems) if the
194
+ // file is still open for writing
196
195
_chan ? . Dispose ( ) ;
196
+ _completionPromise . TrySetResult ( result ) ;
197
197
}
198
198
catch ( Exception ex )
199
199
{
200
200
_completionPromise . TrySetResult ( IOResult . Failed ( _bytesWritten , ex ) ) ;
201
201
}
202
-
203
- _completionPromise . TrySetResult ( IOResult . Success ( _bytesWritten ) ) ;
204
- base . PostStop ( ) ;
205
202
}
206
203
}
207
204
}
0 commit comments