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;
@@ -91,189 +91,148 @@ class GrpcClient {
91
91
}
92
92
}
93
93
94
+ Future <Rep ?> doRpc <Req extends RpcMessage , Rep extends RpcMessage >(
95
+ ResponseStream <Rep > Function (Stream <Req > request) action,
96
+ Req request, {
97
+ bool checkUpdates = false ,
98
+ bool log = true ,
99
+ }) {
100
+ if (log) logger.i ('Sent ${request .repr }' );
101
+ Stream <Rep > replyStream = action (Stream .value (request));
102
+ if (checkUpdates) replyStream = replyStream.doOnData (checkForUpdate);
103
+ if (log) replyStream = replyStream.doOnEach (logGrpc (request));
104
+ return replyStream.lastOrNull;
105
+ }
106
+
94
107
Future <StartReply ?> start (Iterable <String > names) {
95
- final request = StartRequest (
96
- instanceNames: InstanceNames (instanceName: names),
108
+ return doRpc (
109
+ _client.start,
110
+ StartRequest (instanceNames: InstanceNames (instanceName: names)),
111
+ checkUpdates: true ,
97
112
);
98
- logger.i ('Sent ${request .repr }' );
99
- return _client
100
- .start (Stream .value (request))
101
- .doOnData (checkForUpdate)
102
- .doOnEach (logGrpc (request))
103
- .firstOrNull;
104
113
}
105
114
106
115
Future <StopReply ?> stop (Iterable <String > names) {
107
- final request = StopRequest (
108
- instanceNames: InstanceNames (instanceName: names),
116
+ return doRpc (
117
+ _client.stop,
118
+ StopRequest (instanceNames: InstanceNames (instanceName: names)),
109
119
);
110
- logger.i ('Sent ${request .repr }' );
111
- return _client
112
- .stop (Stream .value (request))
113
- .doOnEach (logGrpc (request))
114
- .firstOrNull;
115
120
}
116
121
117
122
Future <SuspendReply ?> suspend (Iterable <String > names) {
118
- final request = SuspendRequest (
119
- instanceNames: InstanceNames (instanceName: names),
123
+ return doRpc (
124
+ _client.suspend,
125
+ SuspendRequest (instanceNames: InstanceNames (instanceName: names)),
120
126
);
121
- logger.i ('Sent ${request .repr }' );
122
- return _client
123
- .suspend (Stream .value (request))
124
- .doOnEach (logGrpc (request))
125
- .firstOrNull;
126
127
}
127
128
128
129
Future <RestartReply ?> restart (Iterable <String > names) {
129
- final request = RestartRequest (
130
- instanceNames: InstanceNames (instanceName: names),
130
+ return doRpc (
131
+ _client.restart,
132
+ RestartRequest (instanceNames: InstanceNames (instanceName: names)),
133
+ checkUpdates: true ,
131
134
);
132
- logger.i ('Sent ${request .repr }' );
133
- return _client
134
- .restart (Stream .value (request))
135
- .doOnData (checkForUpdate)
136
- .doOnEach (logGrpc (request))
137
- .firstOrNull;
138
135
}
139
136
140
137
Future <DeleteReply ?> delete (Iterable <String > names) {
141
- final request = DeleteRequest (
142
- instanceSnapshotPairs: names.map (
143
- (name) => InstanceSnapshotPair (instanceName: name),
138
+ return doRpc (
139
+ _client.delet,
140
+ DeleteRequest (
141
+ instanceSnapshotPairs: names.map (
142
+ (name) => InstanceSnapshotPair (instanceName: name),
143
+ ),
144
144
),
145
145
);
146
- logger.i ('Sent ${request .repr }' );
147
- return _client
148
- .delet (Stream .value (request))
149
- .doOnEach (logGrpc (request))
150
- .firstOrNull;
151
146
}
152
147
153
148
Future <RecoverReply ?> recover (Iterable <String > names) {
154
- final request = RecoverRequest (
155
- instanceNames: InstanceNames (instanceName: names),
149
+ return doRpc (
150
+ _client.recover,
151
+ RecoverRequest (instanceNames: InstanceNames (instanceName: names)),
156
152
);
157
- logger.i ('Sent ${request .repr }' );
158
- return _client
159
- .recover (Stream .value (request))
160
- .doOnEach (logGrpc (request))
161
- .firstOrNull;
162
153
}
163
154
164
155
Future <DeleteReply ?> purge (Iterable <String > names) {
165
- final request = DeleteRequest (
166
- instanceSnapshotPairs: names.map (
167
- (name) => InstanceSnapshotPair (instanceName: name),
156
+ return doRpc (
157
+ _client.delet,
158
+ DeleteRequest (
159
+ purge: true ,
160
+ instanceSnapshotPairs: names.map (
161
+ (name) => InstanceSnapshotPair (instanceName: name),
162
+ ),
168
163
),
169
- purge: true ,
170
164
);
171
- logger.i ('Sent ${request .repr }' );
172
- return _client
173
- .delet (Stream .value (request))
174
- .doOnEach (logGrpc (request))
175
- .firstOrNull;
176
165
}
177
166
178
167
Future <List <VmInfo >> info ([Iterable <String > names = const []]) {
179
- final request = InfoRequest (
180
- instanceSnapshotPairs: names.map (
181
- (name) => InstanceSnapshotPair (instanceName: name),
168
+ return doRpc (
169
+ _client.info,
170
+ checkUpdates: true ,
171
+ log: false ,
172
+ InfoRequest (
173
+ instanceSnapshotPairs: names.map (
174
+ (name) => InstanceSnapshotPair (instanceName: name),
175
+ ),
182
176
),
183
- );
184
- return _client
185
- .info (Stream .value (request))
186
- .doOnData (checkForUpdate)
187
- .last
188
- .then ((r) => r.details.toList ());
177
+ ).then ((r) => r! .details.toList ());
189
178
}
190
179
191
180
Future <MountReply ?> mount (MountRequest request) {
192
- logger.i ('Sent ${request .repr }' );
193
- return _client
194
- .mount (Stream .value (request))
195
- .doOnEach (logGrpc (request))
196
- .firstOrNull;
181
+ return doRpc (_client.mount, request);
197
182
}
198
183
199
184
Future <void > umount (String name, [String ? path]) {
200
- final request = UmountRequest (
201
- targetPaths: [TargetPathInfo (instanceName: name, targetPath: path)],
185
+ return doRpc (
186
+ _client.umount,
187
+ UmountRequest (
188
+ targetPaths: [TargetPathInfo (instanceName: name, targetPath: path)],
189
+ ),
202
190
);
203
- logger.i ('Sent ${request .repr }' );
204
- return _client
205
- .umount (Stream .value (request))
206
- .doOnEach (logGrpc (request))
207
- .firstOrNull;
208
191
}
209
192
210
193
Future <FindReply > find ({bool images = true , bool blueprints = true }) {
211
- final request = FindRequest (
212
- showImages: images,
213
- showBlueprints: blueprints,
214
- );
215
- logger.i ('Sent ${request .repr }' );
216
- return _client.find (Stream .value (request)).doOnEach (logGrpc (request)).last;
194
+ return doRpc (
195
+ _client.find,
196
+ FindRequest (
197
+ showImages: images,
198
+ showBlueprints: blueprints,
199
+ ),
200
+ ).then ((r) => r! );
217
201
}
218
202
219
203
Future <List <NetInterface >> networks () {
220
- final request = NetworksRequest ();
221
- logger.i ('Sent ${request .repr }' );
222
- return _client
223
- .networks (Stream .value (request))
224
- .doOnData (checkForUpdate)
225
- .doOnEach (logGrpc (request))
226
- .last
227
- .then ((r) => r.interfaces);
204
+ return doRpc (
205
+ _client.networks,
206
+ NetworksRequest (),
207
+ checkUpdates: true ,
208
+ ).then ((r) => r! .interfaces);
228
209
}
229
210
230
211
Future <String > version () {
231
- final request = VersionRequest ();
232
- logger.i ('Sent ${request .repr }' );
233
- return _client
234
- .version (Stream .value (request))
235
- .doOnData (checkForUpdate)
236
- .doOnEach (logGrpc (request))
237
- .last
238
- .then ((reply) => reply.version);
212
+ return doRpc (
213
+ _client.version,
214
+ VersionRequest (),
215
+ checkUpdates: true ,
216
+ ).then ((r) => r! .version);
239
217
}
240
218
241
219
Future <String > get (String key) {
242
- final request = GetRequest (key: key);
243
- logger.i ('Sent ${request .repr }' );
244
- return _client
245
- .get (Stream .value (request))
246
- .doOnEach (logGrpc (request))
247
- .last
248
- .then ((reply) => reply.value);
220
+ return doRpc (_client.get , GetRequest (key: key)).then ((r) => r! .value);
249
221
}
250
222
251
223
Future <void > set (String key, String value) {
252
- final request = SetRequest (key: key, val: value);
253
- logger.i ('Sent ${request .repr }' );
254
- return _client
255
- .set (Stream .value (request))
256
- .doOnEach (logGrpc (request))
257
- .firstOrNull;
224
+ return doRpc (_client.set , SetRequest (key: key, val: value));
258
225
}
259
226
260
227
Future <SSHInfo ?> sshInfo (String name) {
261
- final request = SSHInfoRequest (instanceName: [name]);
262
- logger.i ('Sent ${request .repr }' );
263
- return _client
264
- .ssh_info (Stream .value (request))
265
- .doOnEach (logGrpc (request))
266
- .first
267
- .then ((reply) => reply.sshInfo[name]);
228
+ return doRpc (
229
+ _client.ssh_info,
230
+ SSHInfoRequest (instanceName: [name]),
231
+ ).then ((r) => r! .sshInfo[name]);
268
232
}
269
233
270
234
Future <DaemonInfoReply > daemonInfo () {
271
- final request = DaemonInfoRequest ();
272
- logger.i ('Sent ${request .repr }' );
273
- return _client
274
- .daemon_info (Stream .value (request))
275
- .doOnEach (logGrpc (request))
276
- .last;
235
+ return doRpc (_client.daemon_info, DaemonInfoRequest ()).then ((r) => r! );
277
236
}
278
237
}
279
238
@@ -299,3 +258,17 @@ class CustomChannelCredentials extends ChannelCredentials {
299
258
return ctx;
300
259
}
301
260
}
261
+
262
+ extension < T > on Stream <T > {
263
+ Future <T ?> get lastOrNull {
264
+ final completer = Completer <T ?>.sync ();
265
+ T ? result;
266
+ listen (
267
+ (event) => result = event,
268
+ onError: completer.completeError,
269
+ onDone: () => completer.complete (result),
270
+ cancelOnError: true ,
271
+ );
272
+ return completer.future;
273
+ }
274
+ }
0 commit comments