afb-hreq: creation of hreq classe
[src/app-framework-binder.git] / src / config.c
1 /*
2  * Copyright (C) 2015 "IoT.bzh"
3  * Author "Fulup Ar Foll"
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18    References:
19      https://www.gnu.org/software/libmicrohttpd/manual/html_node/index.html#Top
20      http://www-01.ibm.com/support/knowledgecenter/SSB23S_1.1.0.9/com.ibm.ztpf-ztpfdf.doc_put.09/gtpc2/cpp_vsprintf.html?cp=SSB23S_1.1.0.9%2F0-3-8-1-0-16-8
21
22 */
23
24 #include "../include/local-def.h"
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28
29 #define AFB_CONFIG_JTYPE "AFB_config"
30
31 PUBLIC  char *ERROR_LABEL[]=ERROR_LABEL_DEF;
32
33 PUBLIC int verbose;
34 STATIC AFB_errorT   AFBerr [AFB_SUCCESS+1];
35 STATIC json_object *jTypeStatic;
36
37 /* ------------------------------------------------------------------------------
38  * Get localtime and return in a string
39  * ------------------------------------------------------------------------------ */
40
41 PUBLIC char * configTime (void) {
42   static char reqTime [26];
43   time_t tt;
44   struct tm *rt;
45
46   /* Get actual Date and Time */
47   time (&tt);
48   rt = localtime (&tt);
49
50   strftime (reqTime, sizeof (reqTime), "(%d-%b %H:%M)",rt);
51
52   // return pointer on static data
53   return (reqTime);
54 }
55
56 // load config from disk and merge with CLI option
57 PUBLIC AFB_error configLoadFile (AFB_session * session, AFB_config *cliconfig) {
58    static char cacheTimeout [10];
59    int fd;
60    json_object * AFBConfig, *value;
61    
62    // TBD integrate alias-dir array with config-file
63    session->config->aliasdir = cliconfig->aliasdir;
64    session->config->mode = cliconfig->mode;
65
66    // default HTTP port
67    if (cliconfig->httpdPort == 0) session->config->httpdPort=1234;
68    else session->config->httpdPort=cliconfig->httpdPort;
69    
70    // default Plugin API timeout
71    if (cliconfig->apiTimeout == 0) session->config->apiTimeout=DEFLT_API_TIMEOUT;
72    else session->config->apiTimeout=cliconfig->apiTimeout;
73    
74    // default AUTH_TOKEN
75    if (cliconfig->token == NULL) session->config->token= DEFLT_AUTH_TOKEN;
76    else session->config->token=cliconfig->token;
77
78    // cache timeout default one hour
79    if (cliconfig->cacheTimeout == 0) session->config->cacheTimeout=DEFLT_CACHE_TIMEOUT;
80    else session->config->cacheTimeout=cliconfig->cacheTimeout;
81
82    // cache timeout default one hour
83    if (cliconfig->cntxTimeout == 0) session->config->cntxTimeout=DEFLT_CNTX_TIMEOUT;
84    else session->config->cntxTimeout=cliconfig->cntxTimeout;
85
86    if (cliconfig->rootdir == NULL) {
87        session->config->rootdir = getenv("AFBDIR");
88        if (session->config->rootdir == NULL) {
89            session->config->rootdir = malloc (512);
90            strncpy  (session->config->rootdir, getenv("HOME"),512);
91            strncat (session->config->rootdir, "/.AFB",512);
92        }
93        // if directory does not exist createit
94        mkdir (session->config->rootdir,  O_RDWR | S_IRWXU | S_IRGRP);
95    } else {
96        session->config->rootdir =  cliconfig->rootdir;
97    }
98    
99    // if no Angular/HTML5 rootbase let's try '/' as default
100    if  (cliconfig->rootbase == NULL) {
101        session->config->rootbase = "/opa";
102    } else {
103        session->config->rootbase= cliconfig->rootbase;
104    }
105    
106    if  (cliconfig->rootapi == NULL) {
107        session->config->rootapi = "/api";
108    } else {
109        session->config->rootapi= cliconfig->rootapi;
110    }
111
112    if  (cliconfig->ldpaths == NULL) {
113        session->config->ldpaths = PLUGIN_INSTALL_DIR;
114    } else {
115        session->config->ldpaths= cliconfig->ldpaths;
116    }
117
118    // if no session dir create a default path from rootdir
119    if  (cliconfig->sessiondir == NULL) {
120        session->config->sessiondir = malloc (512);
121        strncpy (session->config->sessiondir, session->config->rootdir, 512);
122        strncat (session->config->sessiondir, "/sessions",512);
123    } else {
124        session->config->sessiondir = cliconfig->sessiondir;
125    }
126
127    // if no config dir create a default path from sessiondir
128    if  (cliconfig->configfile == NULL) {
129        session->config->configfile = malloc (512);
130        strncpy (session->config->configfile, session->config->sessiondir, 512);
131        strncat (session->config->configfile, "/AFB-config.json",512);
132    } else {
133        session->config->configfile = cliconfig->configfile;
134    }
135
136    // if no config dir create a default path from sessiondir
137    if  (cliconfig->pidfile == NULL) {
138        session->config->pidfile = malloc (512);
139        strncpy (session->config->pidfile, session->config->sessiondir, 512);
140        strncat (session->config->pidfile, "/AFB-process.pid",512);
141    } else {
142        session->config->pidfile= cliconfig->pidfile;
143    }
144
145    // if no config dir create a default path from sessiondir
146    if  (cliconfig->console == NULL) {
147        session->config->console = malloc (512);
148        strncpy (session->config->console, session->config->sessiondir, 512);
149        strncat (session->config->console, "/AFB-console.out",512);
150    } else {
151        session->config->console= cliconfig->console;
152    }
153    
154    // just upload json object and return without any further processing
155    if((fd = open(session->config->configfile, O_RDONLY)) < 0) {
156       if (verbose) fprintf (stderr, "AFB:notice: config at %s: %s\n", session->config->configfile, strerror(errno));
157       return AFB_EMPTY;
158    }
159
160    // openjson from FD is not public API we need to reopen it !!!
161    close(fd);
162    AFBConfig = json_object_from_file (session->config->configfile);
163
164    // check it is an AFB_config
165    if (json_object_object_get_ex (AFBConfig, "jtype", &value)) {
166       if (strcmp (AFB_CONFIG_JTYPE, json_object_get_string (value))) {
167          fprintf (stderr,"AFB: Error file [%s] is not a valid [%s] type\n ", session->config->configfile, AFB_CONFIG_JTYPE);
168          return AFB_FAIL;
169       }
170    }
171
172    if (!cliconfig->rootdir && json_object_object_get_ex (AFBConfig, "rootdir", &value)) {
173       session->config->rootdir =  strdup (json_object_get_string (value));
174    }
175    
176    if (!cliconfig->rootbase && json_object_object_get_ex (AFBConfig, "rootbase", &value)) {
177       session->config->rootbase =  strdup (json_object_get_string (value));
178    }
179    
180    if (!cliconfig->rootapi && json_object_object_get_ex (AFBConfig, "rootapi", &value)) {
181       session->config->rootapi =  strdup (json_object_get_string (value));
182    }
183    
184    if (!cliconfig->ldpaths && json_object_object_get_ex (AFBConfig, "plugins", &value)) {
185       session->config->ldpaths =  strdup (json_object_get_string (value));
186    }
187
188    if (!cliconfig->setuid && json_object_object_get_ex (AFBConfig, "setuid", &value)) {
189       session->config->setuid = strdup (json_object_get_string (value));
190    }
191    
192    if (!cliconfig->sessiondir && json_object_object_get_ex (AFBConfig, "sessiondir", &value)) {
193       session->config->sessiondir = strdup (json_object_get_string (value));
194    }
195    
196    if (!cliconfig->pidfile && json_object_object_get_ex (AFBConfig, "pidfile", &value)) {
197       session->config->pidfile = strdup (json_object_get_string (value));
198    }
199
200    if (!cliconfig->httpdPort && json_object_object_get_ex (AFBConfig, "httpdPort", &value)) {
201       session->config->httpdPort = json_object_get_int (value);
202    }
203    
204
205    if (!cliconfig->localhostOnly && json_object_object_get_ex (AFBConfig, "localhostonly", &value)) {
206       session->config->localhostOnly = json_object_get_int (value);
207    }
208    
209    if (!cliconfig->cacheTimeout && json_object_object_get_ex (AFBConfig, "cachetimeout", &value)) {
210       session->config->cacheTimeout = json_object_get_int (value);
211    }
212    
213    if (!cliconfig->apiTimeout && json_object_object_get_ex (AFBConfig, "apitimeout", &value)) {
214       session->config->apiTimeout = json_object_get_int (value);
215    }
216    
217    if (!cliconfig->cntxTimeout && json_object_object_get_ex (AFBConfig, "cntxtimeout", &value)) {
218       session->config->cntxTimeout = json_object_get_int (value);
219    }
220    
221    // cacheTimeout is an integer but HTTPd wants it as a string
222    snprintf (cacheTimeout, sizeof (cacheTimeout),"%d", session->config->cacheTimeout);
223    session->cacheTimeout = cacheTimeout; // httpd uses cacheTimeout string version
224    
225    json_object_put   (AFBConfig);    // decrease reference count to free the json object
226
227  
228    
229    return AFB_SUCCESS;
230 }
231
232 // Save the config on disk
233 PUBLIC void configStoreFile (AFB_session * session) {
234    json_object * AFBConfig;
235    time_t rawtime;
236    struct tm * timeinfo;
237    int err;
238
239    AFBConfig =  json_object_new_object();
240
241    // add a timestamp and store session on disk
242    time ( &rawtime );  timeinfo = localtime ( &rawtime );
243    // A copy of the string is made and the memory is managed by the json_object
244    json_object_object_add (AFBConfig, "jtype"         , json_object_new_string (AFB_CONFIG_JTYPE));
245    json_object_object_add (AFBConfig, "timestamp"     , json_object_new_string (asctime (timeinfo)));
246    json_object_object_add (AFBConfig, "rootdir"       , json_object_new_string (session->config->rootdir));
247    json_object_object_add (AFBConfig, "rootapi"       , json_object_new_string (session->config->rootapi));
248    json_object_object_add (AFBConfig, "rootbase"      , json_object_new_string (session->config->rootbase));
249    json_object_object_add (AFBConfig, "plugins"       , json_object_new_string (session->config->ldpaths));
250    json_object_object_add (AFBConfig, "sessiondir"    , json_object_new_string (session->config->sessiondir));
251    json_object_object_add (AFBConfig, "pidfile"       , json_object_new_string (session->config->pidfile));
252    json_object_object_add (AFBConfig, "setuid"        , json_object_new_string (session->config->setuid));
253    json_object_object_add (AFBConfig, "httpdPort"     , json_object_new_int (session->config->httpdPort));
254    json_object_object_add (AFBConfig, "localhostonly" , json_object_new_int (session->config->localhostOnly));
255    json_object_object_add (AFBConfig, "cachetimeout"  , json_object_new_int (session->config->cacheTimeout));
256    json_object_object_add (AFBConfig, "apitimeout"    , json_object_new_int (session->config->apiTimeout));
257    json_object_object_add (AFBConfig, "cntxtimeout"   , json_object_new_int (session->config->cntxTimeout));
258
259    err = json_object_to_file (session->config->configfile, AFBConfig);
260    json_object_put   (AFBConfig);    // decrease reference count to free the json object
261    if (err < 0) {
262       fprintf(stderr, "AFB: Fail to save config on disk [%s]\n ", session->config->configfile);
263    }
264 }
265
266
267 PUBLIC AFB_session *configInit () {
268
269   AFB_session *session;
270   AFB_config  *config;
271   int idx, verbosesav;
272
273
274   session = malloc (sizeof (AFB_session));
275   memset (session,0, sizeof (AFB_session));
276
277   // create config handle
278   config = malloc (sizeof (AFB_config));
279   memset (config,0, sizeof (AFB_config));
280
281   // stack config handle into session
282   session->config = config;
283
284   jTypeStatic = json_object_new_string ("AFB_message");
285
286   // initialise JSON constant messages and increase reference count to make them permanent
287   verbosesav = verbose;
288   verbose = 0;  // run initialisation in silent mode
289
290
291   for (idx = 0; idx <= AFB_SUCCESS; idx++) {
292      AFBerr[idx].level = idx;
293      AFBerr[idx].label = ERROR_LABEL [idx];
294      AFBerr[idx].json  = jsonNewMessage (idx, NULL);
295   }
296   verbose = verbosesav;
297   
298   return (session);
299 }
300
301
302 // get JSON object from error level and increase its reference count
303 PUBLIC json_object *jsonNewStatus (AFB_error level) {
304
305   json_object *target =  AFBerr[level].json;
306   json_object_get (target);
307
308   return (target);
309 }
310
311 // get AFB object type with adequate usage count
312 PUBLIC json_object *jsonNewjtype (void) {
313   json_object_get (jTypeStatic); // increase reference count
314   return (jTypeStatic);
315 }
316
317 // build an ERROR message and return it as a valid json object
318 PUBLIC  json_object *jsonNewMessage (AFB_error level, char* format, ...) {
319    static int count = 0;
320    json_object * AFBResponse;
321    va_list args;
322    char message [512];
323
324    // format message
325    if (format != NULL) {
326        va_start(args, format);
327        vsnprintf (message, sizeof (message), format, args);
328        va_end(args);
329    }
330
331    AFBResponse = json_object_new_object();
332    json_object_object_add (AFBResponse, "jtype", jsonNewjtype ());
333    json_object_object_add (AFBResponse, "status" , json_object_new_string (ERROR_LABEL[level]));
334    if (format != NULL) {
335         json_object_object_add (AFBResponse, "info"   , json_object_new_string (message));
336    }
337    if (verbose) {
338         fprintf (stderr, "AFB:%-6s [%3d]: ", AFBerr [level].label, count++);
339         if (format != NULL) {
340             fprintf (stderr, "%s", message);
341         } else {
342             fprintf (stderr, "No Message");
343         }
344         fprintf (stderr, "\n");
345    }
346
347    return (AFBResponse);
348 }
349
350 // Dump a message on stderr
351 PUBLIC void jsonDumpObject (json_object * jObject) {
352
353    if (verbose) {
354         fprintf (stderr, "AFB:dump [%s]\n", json_object_to_json_string(jObject));
355    }
356 }
357