1
+ import 'dart:async' ;
1
2
import 'dart:io' ;
2
3
3
- import 'package:async/async.dart' ;
4
4
import 'package:fpdart/fpdart.dart' ;
5
5
import 'package:grpc/grpc.dart' ;
6
6
import 'package:protobuf/protobuf.dart' hide RpcClient;
@@ -100,7 +100,7 @@ class GrpcClient {
100
100
.start (Stream .value (request))
101
101
.doOnData (checkForUpdate)
102
102
.doOnEach (logGrpc (request))
103
- .firstOrNull ;
103
+ .lastOrNull ;
104
104
}
105
105
106
106
Future <StopReply ?> stop (Iterable <String > names) {
@@ -111,7 +111,7 @@ class GrpcClient {
111
111
return _client
112
112
.stop (Stream .value (request))
113
113
.doOnEach (logGrpc (request))
114
- .firstOrNull ;
114
+ .lastOrNull ;
115
115
}
116
116
117
117
Future <SuspendReply ?> suspend (Iterable <String > names) {
@@ -122,7 +122,7 @@ class GrpcClient {
122
122
return _client
123
123
.suspend (Stream .value (request))
124
124
.doOnEach (logGrpc (request))
125
- .firstOrNull ;
125
+ .lastOrNull ;
126
126
}
127
127
128
128
Future <RestartReply ?> restart (Iterable <String > names) {
@@ -134,7 +134,7 @@ class GrpcClient {
134
134
.restart (Stream .value (request))
135
135
.doOnData (checkForUpdate)
136
136
.doOnEach (logGrpc (request))
137
- .firstOrNull ;
137
+ .lastOrNull ;
138
138
}
139
139
140
140
Future <DeleteReply ?> delete (Iterable <String > names) {
@@ -147,7 +147,7 @@ class GrpcClient {
147
147
return _client
148
148
.delet (Stream .value (request))
149
149
.doOnEach (logGrpc (request))
150
- .firstOrNull ;
150
+ .lastOrNull ;
151
151
}
152
152
153
153
Future <RecoverReply ?> recover (Iterable <String > names) {
@@ -158,7 +158,7 @@ class GrpcClient {
158
158
return _client
159
159
.recover (Stream .value (request))
160
160
.doOnEach (logGrpc (request))
161
- .firstOrNull ;
161
+ .lastOrNull ;
162
162
}
163
163
164
164
Future <DeleteReply ?> purge (Iterable <String > names) {
@@ -172,7 +172,7 @@ class GrpcClient {
172
172
return _client
173
173
.delet (Stream .value (request))
174
174
.doOnEach (logGrpc (request))
175
- .firstOrNull ;
175
+ .lastOrNull ;
176
176
}
177
177
178
178
Future <List <VmInfo >> info ([Iterable <String > names = const []]) {
@@ -193,7 +193,7 @@ class GrpcClient {
193
193
return _client
194
194
.mount (Stream .value (request))
195
195
.doOnEach (logGrpc (request))
196
- .firstOrNull ;
196
+ .lastOrNull ;
197
197
}
198
198
199
199
Future <void > umount (String name, [String ? path]) {
@@ -204,7 +204,7 @@ class GrpcClient {
204
204
return _client
205
205
.umount (Stream .value (request))
206
206
.doOnEach (logGrpc (request))
207
- .firstOrNull ;
207
+ .lastOrNull ;
208
208
}
209
209
210
210
Future <FindReply > find ({bool images = true , bool blueprints = true }) {
@@ -254,7 +254,7 @@ class GrpcClient {
254
254
return _client
255
255
.set (Stream .value (request))
256
256
.doOnEach (logGrpc (request))
257
- .firstOrNull ;
257
+ .lastOrNull ;
258
258
}
259
259
260
260
Future <SSHInfo ?> sshInfo (String name) {
@@ -263,7 +263,7 @@ class GrpcClient {
263
263
return _client
264
264
.ssh_info (Stream .value (request))
265
265
.doOnEach (logGrpc (request))
266
- .first
266
+ .last
267
267
.then ((reply) => reply.sshInfo[name]);
268
268
}
269
269
@@ -299,3 +299,17 @@ class CustomChannelCredentials extends ChannelCredentials {
299
299
return ctx;
300
300
}
301
301
}
302
+
303
+ extension < T > on Stream <T > {
304
+ Future <T ?> get lastOrNull {
305
+ final completer = Completer <T ?>.sync ();
306
+ T ? result;
307
+ listen (
308
+ (event) => result = event,
309
+ onError: completer.completeError,
310
+ onDone: () => completer.complete (result),
311
+ cancelOnError: true ,
312
+ );
313
+ return completer.future;
314
+ }
315
+ }
0 commit comments