1
- use launchdarkly_server_sdk:: { Context , ContextBuilder , MultiContextBuilder , Reference } ;
1
+ use futures:: future:: FutureExt ;
2
+ use launchdarkly_server_sdk:: {
3
+ Context , ContextBuilder , MigratorBuilder , MultiContextBuilder , Reference ,
4
+ } ;
5
+ use std:: sync:: Arc ;
2
6
use std:: time:: Duration ;
3
7
4
8
const DEFAULT_POLLING_BASE_URL : & str = "https://sdk.launchdarkly.com" ;
@@ -12,7 +16,8 @@ use launchdarkly_server_sdk::{
12
16
} ;
13
17
14
18
use crate :: command_params:: {
15
- ContextBuildParams , ContextConvertParams , ContextParam , ContextResponse , SecureModeHashResponse ,
19
+ ContextBuildParams , ContextConvertParams , ContextParam , ContextResponse ,
20
+ MigrationOperationResponse , MigrationVariationResponse , SecureModeHashResponse ,
16
21
} ;
17
22
use crate :: HttpsConnector ;
18
23
use crate :: {
@@ -24,7 +29,7 @@ use crate::{
24
29
} ;
25
30
26
31
pub struct ClientEntity {
27
- client : Client ,
32
+ client : Arc < Client > ,
28
33
}
29
34
30
35
impl ClientEntity {
@@ -131,10 +136,15 @@ impl ClientEntity {
131
136
client. start_with_default_executor ( ) ;
132
137
client. wait_for_initialization ( Duration :: from_secs ( 5 ) ) . await ;
133
138
134
- Ok ( Self { client } )
139
+ Ok ( Self {
140
+ client : Arc :: new ( client) ,
141
+ } )
135
142
}
136
143
137
- pub fn do_command ( & self , command : CommandParams ) -> Result < Option < CommandResponse > , String > {
144
+ pub async fn do_command (
145
+ & self ,
146
+ command : CommandParams ,
147
+ ) -> Result < Option < CommandResponse > , String > {
138
148
match command. command . as_str ( ) {
139
149
"evaluate" => Ok ( Some ( CommandResponse :: EvaluateFlag (
140
150
self . evaluate ( command. evaluate . ok_or ( "Evaluate params should be set" ) ?) ,
@@ -211,6 +221,132 @@ impl ClientEntity {
211
221
} ,
212
222
) ) )
213
223
}
224
+ "migrationVariation" => {
225
+ let params = command
226
+ . migration_variation
227
+ . ok_or ( "migrationVariation params should be set" ) ?;
228
+
229
+ let ( stage, _) = self . client . migration_variation (
230
+ & params. context ,
231
+ & params. key ,
232
+ params. default_stage ,
233
+ ) ;
234
+
235
+ Ok ( Some ( CommandResponse :: MigrationVariation (
236
+ MigrationVariationResponse { result : stage } ,
237
+ ) ) )
238
+ }
239
+ "migrationOperation" => {
240
+ let params = command
241
+ . migration_operation
242
+ . ok_or ( "migrationOperation params should be set" ) ?;
243
+
244
+ let mut builder = MigratorBuilder :: new ( self . client . clone ( ) ) ;
245
+
246
+ builder = builder
247
+ . read_execution_order ( params. read_execution_order )
248
+ . track_errors ( params. track_errors )
249
+ . track_latency ( params. track_latency )
250
+ . read (
251
+ |payload : & Option < String > | {
252
+ let old_endpoint = params. old_endpoint . clone ( ) ;
253
+ async move {
254
+ let result = send_payload ( & old_endpoint, payload. clone ( ) ) . await ;
255
+ match result {
256
+ Ok ( r) => Ok ( Some ( r) ) ,
257
+ Err ( e) => Err ( e) ,
258
+ }
259
+ }
260
+ . boxed ( )
261
+ } ,
262
+ |payload| {
263
+ let new_endpoint = params. new_endpoint . clone ( ) ;
264
+ async move {
265
+ let result = send_payload ( & new_endpoint, payload. clone ( ) ) . await ;
266
+ match result {
267
+ Ok ( r) => Ok ( Some ( r) ) ,
268
+ Err ( e) => Err ( e) ,
269
+ }
270
+ }
271
+ . boxed ( )
272
+ } ,
273
+ if params. track_consistency {
274
+ Some ( |lhs, rhs| lhs == rhs)
275
+ } else {
276
+ None
277
+ } ,
278
+ )
279
+ . write (
280
+ |payload| {
281
+ let old_endpoint = params. old_endpoint . clone ( ) ;
282
+ async move {
283
+ let result = send_payload ( & old_endpoint, payload. clone ( ) ) . await ;
284
+ match result {
285
+ Ok ( r) => Ok ( Some ( r) ) ,
286
+ Err ( e) => Err ( e) ,
287
+ }
288
+ }
289
+ . boxed ( )
290
+ } ,
291
+ |payload| {
292
+ let new_endpoint = params. new_endpoint . clone ( ) ;
293
+ async move {
294
+ let result = send_payload ( & new_endpoint, payload. clone ( ) ) . await ;
295
+ match result {
296
+ Ok ( r) => Ok ( Some ( r) ) ,
297
+ Err ( e) => Err ( e) ,
298
+ }
299
+ }
300
+ . boxed ( )
301
+ } ,
302
+ ) ;
303
+
304
+ let mut migrator = builder. build ( ) . expect ( "builder failed" ) ;
305
+ match params. operation {
306
+ launchdarkly_server_sdk:: Operation :: Read => {
307
+ let result = migrator
308
+ . read (
309
+ & params. context ,
310
+ params. key ,
311
+ params. default_stage ,
312
+ params. payload ,
313
+ )
314
+ . await ;
315
+
316
+ let payload = match result. result {
317
+ Ok ( payload) => payload. unwrap_or_else ( || "success" . into ( ) ) ,
318
+ Err ( e) => e. to_string ( ) ,
319
+ } ;
320
+
321
+ Ok ( Some ( CommandResponse :: MigrationOperation (
322
+ MigrationOperationResponse { result : payload } ,
323
+ ) ) )
324
+ }
325
+ launchdarkly_server_sdk:: Operation :: Write => {
326
+ let result = migrator
327
+ . write (
328
+ & params. context ,
329
+ params. key ,
330
+ params. default_stage ,
331
+ params. payload ,
332
+ )
333
+ . await ;
334
+
335
+ let payload = match result. authoritative . result {
336
+ Ok ( payload) => payload. unwrap_or_else ( || "success" . into ( ) ) ,
337
+ Err ( e) => e. to_string ( ) ,
338
+ } ;
339
+
340
+ Ok ( Some ( CommandResponse :: MigrationOperation (
341
+ MigrationOperationResponse { result : payload } ,
342
+ ) ) )
343
+ }
344
+ _ => Err ( format ! (
345
+ "Invalid operation requested: {:?}" ,
346
+ params. operation
347
+ ) ) ,
348
+ }
349
+ }
214
350
command => Err ( format ! ( "Invalid command requested: {}" , command) ) ,
215
351
}
216
352
}
@@ -430,3 +566,25 @@ impl Drop for ClientEntity {
430
566
self . client . close ( ) ;
431
567
}
432
568
}
569
+
570
+ async fn send_payload ( endpoint : & str , payload : Option < String > ) -> Result < String , String >
571
+ where
572
+ {
573
+ let client = reqwest:: Client :: new ( ) ;
574
+ let response = client
575
+ . post ( endpoint)
576
+ . body ( payload. unwrap_or_default ( ) )
577
+ . send ( )
578
+ . await
579
+ . expect ( "sending request to SDK test harness" ) ;
580
+
581
+ if response. status ( ) . is_success ( ) {
582
+ let body = response. text ( ) . await . expect ( "read harness response body" ) ;
583
+ Ok ( body. to_string ( ) )
584
+ } else {
585
+ Err ( format ! (
586
+ "requested failed with status code {}" ,
587
+ response. status( )
588
+ ) )
589
+ }
590
+ }
0 commit comments