11// Copyright (c) 2024 Cloudflare, Inc. All rights reserved.
22// SPDX-License-Identifier: BSD-3-Clause
33
4- use anyhow:: { anyhow , Context as _} ;
4+ use anyhow:: Context as _;
55use daphne:: {
66 constants:: DapMediaType ,
7- error:: aborts:: ProblemDetails ,
87 messages:: {
9- taskprov:: TaskprovAdvertisement , AggregateShareReq , AggregationJobInitReq ,
8+ taskprov:: TaskprovAdvertisement , AggregateShare , AggregateShareReq , AggregationJobInitReq ,
109 AggregationJobResp ,
1110 } ,
1211 DapVersion ,
1312} ;
1413use daphne_service_utils:: { bearer_token:: BearerToken , http_headers} ;
15- use prio:: codec:: { ParameterizedDecode as _ , ParameterizedEncode as _} ;
14+ use prio:: codec:: ParameterizedEncode as _;
1615use reqwest:: header;
1716use url:: Url ;
1817
1918use crate :: HttpClient ;
2019
21- use super :: response_to_anyhow ;
20+ use super :: retry_and_decode ;
2221
2322impl HttpClient {
2423 pub async fn submit_aggregation_job_init_req (
@@ -28,45 +27,47 @@ impl HttpClient {
2827 version : DapVersion ,
2928 opts : Options < ' _ > ,
3029 ) -> anyhow:: Result < AggregationJobResp > {
31- let resp = self
32- . put ( url)
33- . body ( agg_job_init_req. get_encoded_with_param ( & version) . unwrap ( ) )
34- . headers ( construct_request_headers (
35- DapMediaType :: AggregationJobInitReq
36- . as_str_for_version ( version)
37- . with_context ( || {
38- format ! ( "AggregationJobInitReq media type is not defined for {version}" )
39- } ) ?,
40- version,
41- opts,
42- ) ?)
43- . send ( )
44- . await
45- . context ( "sending AggregationJobInitReq" ) ?;
46- if resp. status ( ) == 400 {
47- let text = resp. text ( ) . await ?;
48- let problem_details: ProblemDetails =
49- serde_json:: from_str ( & text) . with_context ( || {
50- format ! ( "400 Bad Request: failed to parse problem details document: {text:?}" )
51- } ) ?;
52- Err ( anyhow ! ( "400 Bad Request: {problem_details:?}" ) )
53- } else if resp. status ( ) == 500 {
54- Err ( anyhow:: anyhow!(
55- "500 Internal Server Error: {}" ,
56- resp. text( ) . await ?
57- ) )
58- } else if !resp. status ( ) . is_success ( ) {
59- Err ( response_to_anyhow ( resp) . await ) . context ( "while running an AggregationJobInitReq" )
60- } else {
61- AggregationJobResp :: get_decoded_with_param (
62- & version,
63- & resp
64- . bytes ( )
65- . await
66- . context ( "transfering bytes from the AggregateInitReq" ) ?,
67- )
68- . with_context ( || "failed to parse response to AggregateInitReq from Helper" )
69- }
30+ retry_and_decode ( & version, || async {
31+ self . put ( url. clone ( ) )
32+ . body ( agg_job_init_req. get_encoded_with_param ( & version) . unwrap ( ) )
33+ . headers ( construct_request_headers (
34+ DapMediaType :: AggregationJobInitReq
35+ . as_str_for_version ( version)
36+ . with_context ( || {
37+ format ! ( "AggregationJobInitReq media type is not defined for {version}" )
38+ } ) ?,
39+ version,
40+ opts,
41+ ) ?)
42+ . send ( )
43+ . await
44+ . context ( "sending AggregationJobInitReq" )
45+ } )
46+ . await
47+ }
48+
49+ pub async fn poll_aggregation_job_init (
50+ & self ,
51+ url : Url ,
52+ version : DapVersion ,
53+ opts : Options < ' _ > ,
54+ ) -> anyhow:: Result < AggregationJobResp > {
55+ retry_and_decode ( & version, || async {
56+ self . get ( url. clone ( ) )
57+ . headers ( construct_request_headers (
58+ DapMediaType :: AggregationJobInitReq
59+ . as_str_for_version ( version)
60+ . with_context ( || {
61+ format ! ( "AggregationJobInitReq media type is not defined for {version}" )
62+ } ) ?,
63+ version,
64+ opts,
65+ ) ?)
66+ . send ( )
67+ . await
68+ . context ( "polling aggregation job init req" )
69+ } )
70+ . await
7071 }
7172
7273 pub async fn get_aggregate_share (
@@ -75,42 +76,28 @@ impl HttpClient {
7576 agg_share_req : AggregateShareReq ,
7677 version : DapVersion ,
7778 opts : Options < ' _ > ,
78- ) -> anyhow:: Result < ( ) > {
79- let resp = self
80- . post ( url)
81- . body ( agg_share_req. get_encoded_with_param ( & version) . unwrap ( ) )
82- . headers ( construct_request_headers (
83- DapMediaType :: AggregateShareReq
84- . as_str_for_version ( version)
85- . with_context ( || {
86- format ! ( "AggregateShareReq media type is not defined for {version}" )
87- } ) ?,
88- version,
89- opts,
90- ) ?)
91- . send ( )
92- . await
93- . context ( "sending AggregateShareReq" ) ?;
94- if resp. status ( ) == 400 {
95- let problem_details: ProblemDetails = serde_json:: from_slice (
96- & resp
97- . bytes ( )
98- . await
99- . context ( "transfering bytes for AggregateShareReq" ) ?,
100- )
101- . with_context ( || "400 Bad Request: failed to parse problem details document" ) ?;
102- Err ( anyhow ! ( "400 Bad Request: {problem_details:?}" ) )
103- } else if resp. status ( ) == 500 {
104- Err ( anyhow ! ( "500 Internal Server Error: {}" , resp. text( ) . await ?) )
105- } else if !resp. status ( ) . is_success ( ) {
106- Err ( response_to_anyhow ( resp) . await ) . context ( "while running an AggregateShareReq" )
107- } else {
108- Ok ( ( ) )
109- }
79+ ) -> anyhow:: Result < AggregateShare > {
80+ retry_and_decode ( & ( ) , || async {
81+ self . post ( url. clone ( ) )
82+ . body ( agg_share_req. get_encoded_with_param ( & version) . unwrap ( ) )
83+ . headers ( construct_request_headers (
84+ DapMediaType :: AggregateShareReq
85+ . as_str_for_version ( version)
86+ . with_context ( || {
87+ format ! ( "AggregateShareReq media type is not defined for {version}" )
88+ } ) ?,
89+ version,
90+ opts,
91+ ) ?)
92+ . send ( )
93+ . await
94+ . context ( "sending AggregateShareReq" )
95+ } )
96+ . await
11097 }
11198}
11299
113- #[ derive( Default , Debug ) ]
100+ #[ derive( Default , Debug , Clone , Copy ) ]
114101pub struct Options < ' s > {
115102 pub taskprov_advertisement : Option < & ' s TaskprovAdvertisement > ,
116103 pub bearer_token : Option < & ' s BearerToken > ,
0 commit comments