1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
use crate::request_rate::{ api::Api, duration_to_string::duration_to_string, RequestRate }; // use crate::request_rate use log::info; use std::time::Instant; impl RequestRate { /// This method is not for public consumption. It is for internal use only. /// /// ## Description /// /// This method does the actual rate limiting. It will look up the actual /// effective requests/duration rate and compare it to the targeted /// requests/duration rate. If the current rate exceeds the targeted rate, /// this method will put the thread to sleep until it is ready for the next /// request. /// /// ## Arguments: /// /// * `api` ‧ The API for which to observe the request rate limit. pub fn limit(&mut self, api: &Api) { // Select the ApiLimit requested by the caller: let api_ref = match api { Api::All => &mut self.all, Api::Directions => &mut self.directions, Api::DistanceMatrix => &mut self.distance_matrix, Api::Elevation => &mut self.elevation, Api::Geocoding => &mut self.geocoding, Api::TimeZone => &mut self.time_zone, }; // api match *api_ref { // No request rate is defined for caller's API, do nothing: None => (), // There is a request rate defined for the caller's specified API. // Compare the current rate to the target rate. Put the thread to // sleep if necessary. Some(ref mut rate) => { match rate.current_rate.first_request { // If this is the first request to the API, initialize the // timer. None => { // For some reason this trace! macro can cause a stack // overflow, so it has been commented out for now: /* trace!("Rate limiting is enabled for the `{}` API. First request.", api.to_string()); */ rate.current_rate.first_request = Some(Instant::now()); rate.current_rate.request_count = 1; } // case // If this is not the first request - calculate the elapsed, // time & current rate, compare against the target rate, and // sleep if necessary: Some(first_request) => { // Output logging information: // For some reason these trace! macros can cause a // stack overflow, so they have been commented out for // now: /* trace!( "{} requests to the `{}` API this session. This API's session began {} ago.", rate.current_rate.request_count, api.to_string(), duration_to_string(&first_request.elapsed()) ); */ /* trace!( "Current rate: {}. Target rate: {}.", rate.current_rate, rate.target_rate ); */ // Calculate the current rate and target rate: let target_rate = rate.target_rate.requests as f64 / rate.target_rate.duration.as_secs_f64(); let current_rate = rate.current_rate.request_count as f64 / first_request.elapsed().as_secs_f64(); // If the current rate exceeds the targeted rate, put // the thread to sleep: let difference = current_rate - target_rate; if difference > 0.0 { let sleep_duration = std::time::Duration::from_secs( ((1.0 / target_rate) + difference).round() as u64, ); info!( "Thread is sleeping for {}.", duration_to_string(&sleep_duration) ); std::thread::sleep(sleep_duration); } // if // Increment the request counter: rate.current_rate.request_count += 1; } // case } // match } // case } // match } // fn } // impl