1
+ use std:: iter:: once;
2
+ use std:: sync:: Arc ;
3
+
1
4
use futures:: compat:: Future01CompatExt ;
2
- use futures:: future:: FutureExt ;
5
+ use futures:: future:: { ok, try_join_all} ;
6
+ use futures:: { FutureExt , TryFutureExt } ;
3
7
use futures_legacy:: Future as LegacyFuture ;
4
8
use reqwest:: r#async:: { Client , Response } ;
5
9
use serde:: Deserialize ;
@@ -9,39 +13,74 @@ use domain::{Channel, RepositoryFuture};
9
13
use crate :: domain:: channel:: ChannelRepository ;
10
14
use crate :: infrastructure:: persistence:: api:: ApiPersistenceError ;
11
15
16
+ #[ derive( Clone ) ]
12
17
pub struct ApiChannelRepository {
13
18
pub client : Client ,
14
19
}
15
20
16
- impl ChannelRepository for ApiChannelRepository {
17
- fn all ( & self , identity : & str ) -> RepositoryFuture < Vec < Channel > > {
18
- let list_page_url = |page : u32 | {
19
- format ! (
20
- "http://localhost:8005/channel/list?validator={}&page={}" ,
21
- identity, page
21
+ impl ApiChannelRepository {
22
+ fn fetch_page ( & self , page : u64 , identity : & str ) -> RepositoryFuture < ChannelAllResponse > {
23
+ self . client
24
+ // call Sentry and fetch first page, where validator = identity
25
+ . get (
26
+ format ! (
27
+ "http://localhost:8005/channel/list?validator={}&page={}" ,
28
+ identity, page
29
+ )
30
+ . as_str ( ) ,
22
31
)
23
- } ;
24
- let first_page = self
25
- . client
26
- // call Sentry and fetch first page, where validator = params.identifier
27
- . get ( & list_page_url ( 1 ) )
28
32
. send ( )
29
- . and_then ( |mut res : Response | res. json :: < AllResponse > ( ) )
30
- . map ( |response| response. channels )
33
+ . and_then ( |mut res : Response | res. json :: < ChannelAllResponse > ( ) )
31
34
// @TODO: Error handling
32
- . map_err ( |_error| ApiPersistenceError :: Reading . into ( ) ) ;
35
+ . map_err ( |_error| ApiPersistenceError :: Reading . into ( ) )
36
+ . compat ( )
37
+ . boxed ( )
38
+ }
39
+ }
33
40
34
- // call Sentry again and concat all the Channels in 1 Stream
41
+ impl ChannelRepository for ApiChannelRepository {
42
+ fn all ( & self , identity : & str ) -> RepositoryFuture < Vec < Channel > > {
43
+ let identity = Arc :: new ( identity. to_string ( ) ) ;
44
+ let handle = self . clone ( ) ;
45
+
46
+ let first_page = handle. fetch_page ( 1 , & identity. clone ( ) ) ;
47
+
48
+ // call Sentry again and concat all the Channels in Future
35
49
// fetching them until no more Channels are returned
36
- // @TODO: fetch the rest of the results
50
+ first_page
51
+ . and_then ( move |response| {
52
+ let first_page_future = ok ( response. channels ) . boxed ( ) ;
53
+
54
+ if response. total_pages < 2 {
55
+ first_page_future
56
+ } else {
57
+ let identity = identity. clone ( ) ;
58
+ let futures = ( 2 ..=response. total_pages )
59
+ . map ( |page| {
60
+ handle
61
+ . fetch_page ( page, & identity)
62
+ . map ( |response_result| {
63
+ response_result. and_then ( |response| Ok ( response. channels ) )
64
+ } )
65
+ . boxed ( )
66
+ } )
67
+ . chain ( once ( first_page_future) ) ;
37
68
38
- first_page. compat ( ) . boxed ( )
69
+ try_join_all ( futures)
70
+ . map ( |result_all| {
71
+ result_all
72
+ . and_then ( |all| Ok ( all. into_iter ( ) . flatten ( ) . collect :: < Vec < _ > > ( ) ) )
73
+ } )
74
+ . boxed ( )
75
+ }
76
+ } )
77
+ . boxed ( )
39
78
}
40
79
}
41
80
42
- #[ derive( Deserialize ) ]
81
+ #[ derive( Deserialize , Debug ) ]
43
82
#[ serde( rename_all = "camelCase" ) ]
44
- struct AllResponse {
83
+ struct ChannelAllResponse {
45
84
pub channels : Vec < Channel > ,
46
85
pub total_pages : u64 ,
47
86
}
0 commit comments