@@ -8,6 +8,7 @@ use pallas::ledger::primitives::{PlutusData, ToCanonicalJson};
88use reqwest:: Client ;
99use rocket:: State ;
1010use rocket:: fairing:: { Fairing , Info , Kind } ;
11+ use rocket:: futures:: future:: join_all;
1112use rocket:: http:: { Header , Method , Status } ;
1213use rocket:: response:: content:: RawHtml ;
1314use serde_json:: Value ;
@@ -154,7 +155,7 @@ fn decode_asset_name(hex_name: &str) -> Result<String, Error> {
154155 } )
155156}
156157
157- fn distance_from_center ( x : i32 , y : i32 , center : PositionInput ) -> i32 {
158+ fn distance_from_center ( x : i32 , y : i32 , center : & PositionInput ) -> i32 {
158159 ( x - center. x ) . abs ( ) + ( y - center. y ) . abs ( )
159160}
160161
@@ -351,6 +352,103 @@ async fn fetch_utxos_by_address(
351352 . map_err ( |e| Error :: new ( e. to_string ( ) ) )
352353}
353354
355+ async fn ships_in_radius (
356+ api : & BlockfrostAPI ,
357+ spacetime_address : & str ,
358+ spacetime_policy_id : & str ,
359+ pellet_policy_id : & str ,
360+ radius : i32 ,
361+ center : & PositionInput ,
362+ ) -> Result < Vec < PositionalInterface > , Error > {
363+ Ok (
364+ fetch_utxos_by_policy ( api, spacetime_address, spacetime_policy_id)
365+ . await ?
366+ . into_iter ( )
367+ . map ( |x| {
368+ Ship :: try_from ( (
369+ spacetime_policy_id. to_string ( ) ,
370+ pellet_policy_id. to_string ( ) ,
371+ x,
372+ ) )
373+ } )
374+ . collect :: < Result < Vec < Ship > , Error > > ( ) ?
375+ . into_iter ( )
376+ . filter ( |ship| {
377+ let distance = distance_from_center ( ship. position . x , ship. position . y , center) ;
378+ distance < radius
379+ } )
380+ . map ( |ship| PositionalInterface :: Ship ( ship. clone ( ) ) )
381+ . collect :: < Vec < PositionalInterface > > ( ) ,
382+ )
383+ }
384+
385+ async fn pellets_in_radius (
386+ api : & BlockfrostAPI ,
387+ pellet_address : & str ,
388+ pellet_policy_id : & str ,
389+ radius : i32 ,
390+ center : & PositionInput ,
391+ ) -> Result < Vec < PositionalInterface > , Error > {
392+ Ok (
393+ fetch_utxos_by_policy ( api, pellet_address, pellet_policy_id)
394+ . await ?
395+ . into_iter ( )
396+ . map ( |x| Pellet :: try_from ( ( pellet_policy_id. to_string ( ) , x) ) )
397+ . collect :: < Result < Vec < Pellet > , Error > > ( ) ?
398+ . into_iter ( )
399+ . filter ( |pellet| {
400+ let distance = distance_from_center ( pellet. position . x , pellet. position . y , center) ;
401+ distance < radius
402+ } )
403+ . map ( |pellet| PositionalInterface :: Pellet ( pellet. clone ( ) ) )
404+ . collect :: < Vec < PositionalInterface > > ( ) ,
405+ )
406+ }
407+
408+ async fn asteria_in_radius (
409+ api : & BlockfrostAPI ,
410+ asteria_address : & str ,
411+ spacetime_policy_id : & str ,
412+ radius : i32 ,
413+ center : & PositionInput ,
414+ ) -> Result < Option < PositionalInterface > , Error > {
415+ for utxo in fetch_utxos_by_address ( api, asteria_address) . await ? {
416+ let datum_json = inline_datum_json ( & utxo. inline_datum ) ?;
417+ let spacetime_policy = datum_bytes ( & datum_json, 1 ) ?;
418+ if spacetime_policy != spacetime_policy_id {
419+ continue ;
420+ }
421+ let asteria = Asteria :: try_from ( utxo) ?;
422+
423+ let distance = distance_from_center ( asteria. position . x , asteria. position . y , center) ;
424+ if distance >= radius {
425+ continue ;
426+ }
427+
428+ return Ok ( Some ( PositionalInterface :: Asteria ( asteria) ) ) ;
429+ }
430+ Ok ( None )
431+ }
432+
433+ async fn tokens_in_radius (
434+ api : & BlockfrostAPI ,
435+ pellet_address : & str ,
436+ token : & TokenInput ,
437+ radius : i32 ,
438+ center : & PositionInput ,
439+ ) -> Result < Vec < PositionalInterface > , Error > {
440+ Ok ( fetch_utxos_by_policy ( api, pellet_address, & token. policy_id )
441+ . await ?
442+ . into_iter ( )
443+ . map ( |utxo| Token :: try_from ( ( token. clone ( ) , utxo) ) )
444+ . collect :: < Result < Vec < Token > , Error > > ( ) ?
445+ . into_iter ( )
446+ . filter ( |token| distance_from_center ( token. position . x , token. position . y , center) <= radius)
447+ . filter ( |token| token. amount > 0 )
448+ . map ( PositionalInterface :: Token )
449+ . collect ( ) )
450+ }
451+
354452struct QueryRoot ;
355453
356454#[ derive( Clone ) ]
@@ -560,75 +658,35 @@ impl QueryRoot {
560658
561659 let mut map_objects = Vec :: new ( ) ;
562660
563- for utxo in fetch_utxos_by_policy ( api, & spacetime_address, & spacetime_policy_id) . await ? {
564- let ship =
565- Ship :: try_from ( ( spacetime_policy_id. clone ( ) , pellet_policy_id. clone ( ) , utxo) ) ?;
566- let distance = distance_from_center ( ship. position . x , ship. position . y , center) ;
567- if distance >= radius {
568- continue ;
569- }
570-
571- map_objects. push ( PositionalInterface :: Ship ( ship) ) ;
572- }
573-
574- for utxo in fetch_utxos_by_policy ( api, & pellet_address, & pellet_policy_id) . await ? {
575- let pellet = Pellet :: try_from ( ( pellet_policy_id. clone ( ) , utxo) ) ?;
576- let distance = distance_from_center ( pellet. position . x , pellet. position . y , center) ;
577- if distance >= radius {
578- continue ;
579- }
580-
581- if pellet. spacetime_policy . id . to_string ( ) != spacetime_policy_id {
582- continue ;
583- }
584-
585- if pellet. fuel <= 0 {
586- continue ;
587- }
588-
589- map_objects. push ( PositionalInterface :: Pellet ( pellet) ) ;
590- }
591-
592- for utxo in fetch_utxos_by_address ( api, & asteria_address) . await ? {
593- let datum_json = inline_datum_json ( & utxo. inline_datum ) ?;
594- let spacetime_policy = datum_bytes ( & datum_json, 1 ) ?;
595- if spacetime_policy != spacetime_policy_id {
596- continue ;
597- }
598- let asteria = Asteria :: try_from ( utxo) ?;
599-
600- let distance = distance_from_center ( asteria. position . x , asteria. position . y , center) ;
601- if distance >= radius {
602- continue ;
603- }
604-
605- map_objects. push ( PositionalInterface :: Asteria ( asteria) ) ;
606- }
607-
608- if let Some ( tokens) = tokens {
609- for token in tokens {
610- let token_utxos =
611- fetch_utxos_by_policy ( api, & pellet_address, & token. policy_id ) . await ?;
612-
613- for utxo in token_utxos {
614- let map_token = Token :: try_from ( ( token. clone ( ) , utxo) ) ?;
615- let distance =
616- distance_from_center ( map_token. position . x , map_token. position . y , center) ;
617- if distance >= radius {
618- continue ;
619- }
620-
621- if map_token. spacetime_policy . id . to_string ( ) != spacetime_policy_id {
622- continue ;
623- }
624-
625- if map_token. amount <= 0 {
626- continue ;
627- }
628-
629- map_objects. push ( PositionalInterface :: Token ( map_token) ) ;
661+ let ( ships, pellets, asteria, tokens) = tokio:: join!(
662+ ships_in_radius(
663+ api,
664+ & spacetime_address,
665+ & spacetime_policy_id,
666+ & pellet_policy_id,
667+ radius,
668+ & center,
669+ ) ,
670+ pellets_in_radius( api, & pellet_address, & pellet_policy_id, radius, & center) ,
671+ asteria_in_radius( api, & asteria_address, & spacetime_policy_id, radius, & center) ,
672+ async {
673+ match tokens. as_ref( ) . map( |tokens| {
674+ tokens
675+ . iter( )
676+ . map( |token| tokens_in_radius( api, & pellet_address, token, radius, & center) )
677+ . collect:: <Vec <_>>( )
678+ } ) {
679+ Some ( futs) => join_all( futs) . await ,
680+ None => Vec :: new( ) ,
630681 }
631682 }
683+ ) ;
684+
685+ map_objects. extend ( ships?) ;
686+ map_objects. extend ( pellets?) ;
687+ map_objects. extend ( asteria?. into_iter ( ) ) ;
688+ for token_objects in tokens {
689+ map_objects. extend ( token_objects?) ;
632690 }
633691
634692 Ok ( map_objects)
0 commit comments