From 2b5d155654d853abf1fb885bf9d8b9b059f17e6b Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Mon, 12 Feb 2018 14:28:23 -0800 Subject: binding: weather: update stats every 15 minutes To reduce API calls to OpenWeatherMap only update weather stats every 15 minutes. Changes that were required: * add glib-2.0 dependecy * adding rwlock to url data * g_timeout_add_seconds schedules an weather update every 15 minutes Bug-AGL: SPEC-1273 Change-Id: I09b92faf17830f305275dad7f4545cf64ebb43a2 Signed-off-by: Matt Ranostay --- binding/afm-weather-binding.c | 94 +++++++++++++++++++++++++++++++++---------- conf.d/cmake/config.cmake | 3 ++ 2 files changed, 75 insertions(+), 22 deletions(-) diff --git a/binding/afm-weather-binding.c b/binding/afm-weather-binding.c index 1103722..4c2418d 100644 --- a/binding/afm-weather-binding.c +++ b/binding/afm-weather-binding.c @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include @@ -33,16 +35,29 @@ #define OPENWEATHER_URL "http://api.openweathermap.org/data/2.5/weather?lat=%.4f&lon=%.4f&units=imperial&APPID=%s" struct { - char *api_key; - char url[128]; - char buffer[1024]; + gchar *api_key; + gchar *url; + gchar buffer[1024]; } data; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_event weather_event; +// Forward declaration +gboolean update_weather_data(gpointer ptr); + +static void *weather_loop_thread(void *ptr) +{ + g_timeout_add_seconds(900, update_weather_data, NULL); + + g_main_loop_run(g_main_loop_new(NULL, FALSE)); + + return NULL; +} + static int init() { + pthread_t thread_id; json_object *response, *query; int ret; @@ -58,7 +73,7 @@ static int init() ret = afb_service_call_sync("persistence", "read", query, &response); if (ret < 0) { - data.api_key = strdup(OPENWEATHER_API_KEY); + data.api_key = g_strdup(OPENWEATHER_API_KEY); AFB_WARNING("Cannot get OPENWEATHERMAP_API_KEY from persistence storage, defaulting to %s", data.api_key); } else { json_object *jresp = NULL; @@ -66,7 +81,7 @@ static int init() json_object_object_get_ex(response, "response", &jresp); json_object_object_get_ex(jresp, "value", &jresp); - data.api_key = strdup(json_object_get_string(jresp)); + data.api_key = g_strdup(json_object_get_string(jresp)); AFB_NOTICE("OPENWEATHERMAP_API_KEY retrieved from persistence: %s", data.api_key); } @@ -92,7 +107,7 @@ static int init() weather_event = afb_daemon_make_event("weather"); - return 0; + return pthread_create(&thread_id, NULL, weather_loop_thread, NULL); } static size_t weather_cb(char *ptr, size_t size, size_t nmemb, void *usr) @@ -103,7 +118,7 @@ static size_t weather_cb(char *ptr, size_t size, size_t nmemb, void *usr) if (realsize > (sizeof(data.buffer) - 1)) return -ENOMEM; - pthread_mutex_lock(&mutex); + pthread_rwlock_rdlock(&rwlock); memcpy(data.buffer, ptr, realsize); data.buffer[realsize] = '\0'; @@ -113,16 +128,45 @@ static size_t weather_cb(char *ptr, size_t size, size_t nmemb, void *usr) if (jresp) json_object_object_add(jresp, "url", json_object_new_string(data.url)); - pthread_mutex_unlock(&mutex); + pthread_rwlock_unlock(&rwlock); + afb_event_push(weather_event, jresp); return realsize; } +gboolean update_weather_data(gpointer ptr) +{ + CURL *ch; + + pthread_rwlock_rdlock(&rwlock); + + if (data.url == NULL) { + pthread_rwlock_unlock(&rwlock); + return TRUE; + } + + ch = curl_easy_init(); + + if (ch == NULL) { + pthread_rwlock_unlock(&rwlock); + return TRUE; + } + + curl_easy_setopt(ch, CURLOPT_URL, data.url); + curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, weather_cb); + + (void) curl_easy_perform(ch); + curl_easy_cleanup(ch); + + pthread_rwlock_unlock(&rwlock); + + return TRUE; +} + static void onevent(const char *event, struct json_object *object) { json_object *val = NULL; - CURL *ch = NULL; double latitude, longitude; int ret; @@ -138,31 +182,37 @@ static void onevent(const char *event, struct json_object *object) if (!ret) return; longitude = json_object_get_double(val); + ret = 0; - sprintf(data.url, OPENWEATHER_URL, latitude, longitude, data.api_key); + pthread_rwlock_wrlock(&rwlock); - ch = curl_easy_init(); - if (ch == NULL) - return; + if (data.url != NULL) { + g_free(data.url); + data.url = NULL; + ret = -1; + } - curl_easy_setopt(ch, CURLOPT_URL, data.url); - curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, weather_cb); + data.url = g_strdup_printf(OPENWEATHER_URL, latitude, longitude, data.api_key); - (void) curl_easy_perform(ch); - curl_easy_cleanup(ch); + pthread_rwlock_unlock(&rwlock); + + // Initial Weather Data + if (data.url != NULL && !ret) + update_weather_data(NULL); } static void current_weather(struct afb_req request) { json_object *jresp = NULL; - pthread_mutex_lock(&mutex); + pthread_rwlock_rdlock(&rwlock); + jresp = json_tokener_parse(data.buffer); if (jresp) json_object_object_add(jresp, "url", json_object_new_string(data.url)); - pthread_mutex_unlock(&mutex); + pthread_rwlock_unlock(&rwlock); if (jresp == NULL) { afb_req_fail(request, "failed", "No weather data currently"); @@ -211,8 +261,8 @@ static void api_key(struct afb_req request) } if (data.api_key != NULL) { - free(data.api_key); - data.api_key = strdup(value); + g_free(data.api_key); + data.api_key = g_strdup(value); } afb_req_success(request, jresp, NULL); diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake index 2ea55a9..3b70742 100644 --- a/conf.d/cmake/config.cmake +++ b/conf.d/cmake/config.cmake @@ -65,6 +65,9 @@ set (gcc_minimal_version 4.9) # ----------------------------- set (PKG_REQUIRED_LIST json-c + glib-2.0 + gio-2.0 + gobject-2.0 libcurl libsystemd>=222 afb-daemon -- cgit 1.2.3-korg