/* * Copyright (C) 2016-2020 "IoT.bzh" * * Author "Romain Forlot" * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define _GNU_SOURCE #include #include #include #include #include "platform-info-binding.h" #include "platform-info-devices.h" #ifndef PLATFORM_INFO_DIR #define PLATFORM_INFO_DIR "/etc/platform-info" #endif #ifndef HOTPLUG_NS #define HOTPLUG_NS "hotplug" #endif void afv_get(afb_req_t req) { pinfo_api_ctx_t *api_ctx = (pinfo_api_ctx_t*)afb_api_get_userdata(req->api); if(api_ctx) { json_object *result = NULL; json_object *args = afb_req_json(req); switch (json_object_get_type(args)) { case json_type_null: result = api_ctx->info; break; case json_type_string: { char *json_path = NULL; char *full_json_path = NULL; full_json_path = strdupa(json_object_get_string(args)); result = api_ctx->info; for(json_path = strtok(full_json_path, "."); json_path && *json_path; json_path = strtok(NULL, ".")) { if(! json_object_object_get_ex(result, json_path, &result)) { afb_req_fail(req, "A key hasn't been found in JSON path.", json_path); return; } } break; } default: afb_req_fail(req, "Type error", "Argument type is unknown, you must provide a string only"); return; } afb_req_success(req, json_object_get(result), NULL); } else { afb_req_fail(req,"failed","The API contains no context!"); } } void afv_set(afb_req_t req) { json_object *platform_info = (json_object*) afb_api_get_userdata(req->api); json_object *args = afb_req_json(req); #if (JSON_C_VERSION_MAJOR_VERSION == 0 && JSON_C_VERSION_MINOR_VERSION >= 13) if(json_object_object_add(platform_info, HOTPLUG_NS, args)) { afb_req_fail(req, "Addition fails", NULL); return; } #else json_object_object_add(platform_info, HOTPLUG_NS, args); #endif afb_req_success(req, NULL, NULL); } // TODO RFOR: interface with inotify void afv_unsubscribe(afb_req_t req) { pinfo_client_ctx_t* client_ctx = NULL; client_ctx = (pinfo_client_ctx_t*)afb_req_context_get(req); if(client_ctx) { const char* event_str = afb_req_value(req,"event"); if(event_str && strcmp("monitor-devices",event_str) == 0) { afb_req_unsubscribe(req,client_ctx->ev_devs_changed); afb_req_context_clear(req); afb_req_success(req,NULL, NULL); } else { afb_req_fail(req,"failed","No 'event' value provided."); } } else { afb_req_fail(req,"failed","No context available for the client."); } } void afv_subscribe(afb_req_t req) { const char* event_str = NULL; event_str = afb_req_value(req,"event"); if(event_str && strcmp("monitor-devices",event_str) == 0) { if(!afb_req_context_get(req)) { if(pinfo_device_monitor(req) == PINFO_OK) { afb_req_success(req,NULL,NULL); } else { afb_req_fail(req,"failed","Unable to create new context"); } } else { afb_req_fail(req,"failed","The client already subscribed."); } } else { afb_req_fail(req,"failed","Invalid event subscription"); } } static json_object* afv_static_info(const char* dir) { struct dirent* dir_ent = NULL; DIR* dir_handle = opendir(dir); json_object* static_info = NULL; if (! dir_handle) { AFB_ERROR("The directory %s does not exist.", PLATFORM_INFO_DIR); return NULL; } static_info = json_object_new_object(); while( (dir_ent = readdir(dir_handle)) != NULL) { if(dir_ent->d_type == DT_REG && dir_ent->d_name[0] != '.') { json_object* current_file = NULL; size_t filepath_len = strlen(PLATFORM_INFO_DIR) + strlen(dir_ent->d_name) + 2; char *filepath = alloca(filepath_len); filepath = strncpy(filepath, PLATFORM_INFO_DIR, filepath_len); filepath = strncat(filepath, "/", filepath_len - strlen(filepath) - 1); filepath = strncat(filepath, dir_ent->d_name, filepath_len - strlen(filepath) - 1); AFB_DEBUG("File in processing: %s", filepath); current_file = json_object_from_file(filepath); #if (JSON_C_VERSION_MAJOR_VERSION == 0 && JSON_C_VERSION_MINOR_VERSION >= 13) const char *error = NULL; if( (error = json_util_get_last_err()) ) { AFB_NOTICE("This file '%s' isn't a JSON file or have error: %s. len: %ld", filepath, error, filepath_len); continue; } #else if( current_file == NULL ) { AFB_NOTICE("This file '%s' isn't a JSON file or have error.", filepath); continue; } #endif wrap_json_object_add(static_info, current_file); AFB_DEBUG("JSON loaded: %s", json_object_to_json_string_ext(current_file,JSON_C_TO_STRING_PRETTY)); } } return static_info; } void afv_scan(afb_req_t req) { json_object* jres = NULL; json_object* jfilter = NULL; json_object* jmask = NULL; json_object* jargs = afb_req_json(req); if(json_object_is_type(jargs,json_type_object)) { json_object_object_get_ex(jargs,"filter",&jfilter); json_object_object_get_ex(jargs,"mask",&jmask); } jres = pinfo_device_scan(jfilter,jmask); if(jres) { afb_req_success(req,jres,"Scan success"); } else { afb_req_fail(req,"failed","Scan failed"); } } int init(afb_api_t api) { // Initializing the platform_info binding object and associated it to // the api pinfo_api_ctx_t *api_ctx = NULL; int ret = PINFO_OK; api_ctx = malloc(sizeof(*api_ctx)); if(api_ctx) { api_ctx->info = afv_static_info(PLATFORM_INFO_DIR); AFB_API_DEBUG(api,"The API static data: %s", json_object_to_json_string_ext(api_ctx->info, JSON_C_TO_STRING_PRETTY)); api_ctx->client_count = 0; afb_api_set_userdata(api, (void*)api_ctx); } else { AFB_API_WARNING(api,"Failed to load the static data"); ret = PINFO_ERR; } return ret; }