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 ;
26use std:: time:: Duration ;
37
48const DEFAULT_POLLING_BASE_URL : & str = "https://sdk.launchdarkly.com" ;
@@ -12,7 +16,8 @@ use launchdarkly_server_sdk::{
1216} ;
1317
1418use crate :: command_params:: {
15- ContextBuildParams , ContextConvertParams , ContextParam , ContextResponse , SecureModeHashResponse ,
19+ ContextBuildParams , ContextConvertParams , ContextParam , ContextResponse ,
20+ MigrationOperationResponse , MigrationVariationResponse , SecureModeHashResponse ,
1621} ;
1722use crate :: HttpsConnector ;
1823use crate :: {
@@ -24,7 +29,7 @@ use crate::{
2429} ;
2530
2631pub struct ClientEntity {
27- client : Client ,
32+ client : Arc < Client > ,
2833}
2934
3035impl ClientEntity {
@@ -131,10 +136,15 @@ impl ClientEntity {
131136 client. start_with_default_executor ( ) ;
132137 client. wait_for_initialization ( Duration :: from_secs ( 5 ) ) . await ;
133138
134- Ok ( Self { client } )
139+ Ok ( Self {
140+ client : Arc :: new ( client) ,
141+ } )
135142 }
136143
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 > {
138148 match command. command . as_str ( ) {
139149 "evaluate" => Ok ( Some ( CommandResponse :: EvaluateFlag (
140150 self . evaluate ( command. evaluate . ok_or ( "Evaluate params should be set" ) ?) ,
@@ -211,6 +221,132 @@ impl ClientEntity {
211221 } ,
212222 ) ) )
213223 }
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+ }
214350 command => Err ( format ! ( "Invalid command requested: {}" , command) ) ,
215351 }
216352 }
@@ -430,3 +566,25 @@ impl Drop for ClientEntity {
430566 self . client . close ( ) ;
431567 }
432568}
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