Skip to content

Commit

Permalink
fix: geo location caching
Browse files Browse the repository at this point in the history
  • Loading branch information
RouHim committed Jun 8, 2022
1 parent 5dc3d6b commit 345f1df
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 13 deletions.
31 changes: 31 additions & 0 deletions src/geo_location_cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use evmap::{ReadHandle, WriteHandle};

/// Holds the geo location cache reader and writer
pub struct GeoLocationCache {
kv_reader: ReadHandle<String, String>,
kv_writer: WriteHandle<String, String>,
}

/// Initializes the geo location cache
pub fn init() -> GeoLocationCache {
let (kv_reader, kv_writer) = evmap::new::<String, String>();
GeoLocationCache {
kv_reader,
kv_writer,
}
}

impl GeoLocationCache {
pub fn contains_key(&self, key: &str) -> bool {
self.kv_reader.contains_key(key)
}

pub fn get(&self, key: &str) -> Option<String> {
self.kv_reader.get_one(key).map(|t| t.to_string())
}

pub fn insert(&mut self, key: String, value: String) {
self.kv_writer.insert(key, value);
self.kv_writer.refresh();
}
}
6 changes: 5 additions & 1 deletion src/integration_test_resources_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use rand::Rng;

use crate::geo_location::GeoLocation;
use crate::resource_reader::{RemoteResource, ResourceReader};
use crate::{resource_endpoint, resource_processor, resource_reader, scheduler};
use crate::{
geo_location_cache, resource_endpoint, resource_processor, resource_reader, scheduler,
};

const TEST_JPEG_EXIF_URL: &str =
"https://raw.githubusercontent.com/ianare/exif-samples/master/jpg/gps/DSCN0010.jpg";
Expand Down Expand Up @@ -314,10 +316,12 @@ fn build_app(
> {
scheduler::init();
scheduler::fetch_resources(resource_reader.clone(), kv_writer_mutex.clone());
let geo_location_cache = Arc::new(Mutex::new(geo_location_cache::init()));
App::new()
.app_data(web::Data::new(kv_reader))
.app_data(web::Data::new(resource_reader))
.app_data(web::Data::new(kv_writer_mutex))
.app_data(web::Data::new(geo_location_cache.clone()))
.service(
web::scope("/api/resources")
.service(resource_endpoint::list_all_resources)
Expand Down
5 changes: 5 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use actix_web::{middleware, web, App, HttpResponse, HttpServer};
mod config_endpoint;
mod exif_reader;
mod geo_location;
mod geo_location_cache;
mod image_processor;
mod resource_endpoint;
mod resource_processor;
Expand Down Expand Up @@ -48,13 +49,17 @@ async fn main() -> std::io::Result<()> {
// Fetch resources for the first time
scheduler::fetch_resources(resource_reader.clone(), kv_writer_mutex.clone());

// Initialize geo location cache
let geo_location_cache = Arc::new(Mutex::new(geo_location_cache::init()));

// Run the actual web server and hold the main thread here
println!("Launching webserver 🚀");
let http_server_result = HttpServer::new(move || {
App::new()
.app_data(web::Data::new(kv_reader.clone()))
.app_data(web::Data::new(resource_reader.clone()))
.app_data(web::Data::new(kv_writer_mutex.clone()))
.app_data(web::Data::new(geo_location_cache.clone()))
.wrap(middleware::Logger::default()) // enable logger
.service(
web::scope("/api/resources")
Expand Down
10 changes: 7 additions & 3 deletions src/resource_endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ use std::sync::{Arc, Mutex};
use actix_web::get;
use actix_web::web;
use actix_web::HttpResponse;
use evmap::{ReadHandle, WriteHandle};
use evmap::ReadHandle;

use crate::geo_location_cache::GeoLocationCache;
use crate::resource_reader::{RemoteResource, ResourceReader};
use crate::{image_processor, resource_processor};

Expand Down Expand Up @@ -184,15 +185,18 @@ pub async fn get_resource_metadata_by_id(
pub async fn get_resource_metadata_description_by_id(
resources_id: web::Path<String>,
kv_reader: web::Data<ReadHandle<String, String>>,
kv_writer_mutex: web::Data<Arc<Mutex<WriteHandle<String, String>>>>,
geo_location_cache_mutex: web::Data<Arc<Mutex<GeoLocationCache>>>,
) -> HttpResponse {
let resource = kv_reader
.get_one(resources_id.as_str())
.map(|value| value.to_string())
.and_then(|resource_json_string| serde_json::from_str(resource_json_string.as_str()).ok());

let display_value = resource.map(|resource| {
resource_processor::build_display_value(resource, kv_writer_mutex.get_ref().clone())
resource_processor::build_display_value(
resource,
geo_location_cache_mutex.get_ref().clone(),
)
});

if let Some(display_value) = display_value {
Expand Down
18 changes: 9 additions & 9 deletions src/resource_processor.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use std::env;
use std::sync::{Arc, Mutex};

use evmap::{ReadHandle, WriteHandle};
use evmap::ReadHandle;
use rand::prelude::SliceRandom;
use rand::Rng;
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};

use crate::geo_location;
use crate::geo_location_cache::GeoLocationCache;
use crate::resource_reader::RemoteResource;

pub fn md5(string: &str) -> String {
Expand Down Expand Up @@ -49,7 +50,7 @@ pub fn get_all(kv_reader: &ReadHandle<String, String>) -> Vec<String> {
/// The display value contains the date and location of a resource
pub async fn build_display_value(
resource: RemoteResource,
kv_writer_mutex: Arc<Mutex<WriteHandle<String, String>>>,
geo_location_cache_mutex: Arc<Mutex<GeoLocationCache>>,
) -> String {
let mut display_value: String = String::new();

Expand All @@ -59,7 +60,7 @@ pub async fn build_display_value(
}

// Append city name
let city_name = get_city_name(resource, kv_writer_mutex.clone()).await;
let city_name = get_city_name(resource, geo_location_cache_mutex.clone()).await;
if let Some(city_name) = city_name {
display_value.push_str(", ");
display_value.push_str(city_name.as_str());
Expand All @@ -73,31 +74,30 @@ pub async fn build_display_value(
/// If not, the city name is taken from the geo location service
async fn get_city_name(
resource: RemoteResource,
kv_writer_mutex: Arc<Mutex<WriteHandle<String, String>>>,
geo_location_cache_mutex: Arc<Mutex<GeoLocationCache>>,
) -> Option<String> {
let resource_location = resource.location?;
let resource_location_string = resource_location.to_string();

// First check cache
if kv_writer_mutex
if geo_location_cache_mutex
.lock()
.unwrap()
.contains_key(resource_location_string.as_str())
{
kv_writer_mutex
geo_location_cache_mutex
.lock()
.unwrap()
.get_one(resource_location_string.as_str())
.get(resource_location_string.as_str())
.map(|city_name| city_name.to_string())
} else {
// Get city name
let city_name = geo_location::resolve_city_name(resource_location).await;

if let Some(city_name) = &city_name {
// Write to cache
let mut kv_writer = kv_writer_mutex.lock().unwrap();
let mut kv_writer = geo_location_cache_mutex.lock().unwrap();
kv_writer.insert(resource_location_string, city_name.clone());
kv_writer.refresh();
}

city_name
Expand Down

0 comments on commit 345f1df

Please sign in to comment.