2 * Copyright (C) 2015 "IoT.bzh"
3 * Author "Fulup Ar Foll"
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.
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.
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/>.
20 #include "local-def.h"
25 #include <sys/types.h>
27 #define AFB_SESSION_JTYPE "AFB_session"
28 #define AFB_SESSION_JLIST "AFB_sessions"
29 #define AFB_SESSION_JINFO "AFB_infos"
31 #define AFB_CURRENT_SESSION "active-session" // file link name within sndcard dir
32 #define AFB_DEFAULT_SESSION "current-session" // should be in sync with UI
37 // verify we can read/write in session dir
38 PUBLIC AFB_error sessionCheckdir (AFB_session *session) {
42 // in case session dir would not exist create one
43 if (verbose) fprintf (stderr, "AFB:notice checking session dir [%s]\n", session->config->sessiondir);
44 mkdir(session->config->sessiondir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
46 // change for session directory
47 err = chdir(session->config->sessiondir);
49 fprintf(stderr,"AFB: Fail to chdir to %s error=%s\n", session->config->sessiondir, strerror(err));
53 // verify we can write session in directory
54 json_object *dummy= json_object_new_object();
55 json_object_object_add (dummy, "checked" , json_object_new_int (getppid()));
56 err = json_object_to_file ("./AFB-probe.json", dummy);
57 if (err < 0) return err;
62 // let's return only sessions files
63 STATIC int fileSelect (const struct dirent *entry) {
64 return (strstr (entry->d_name, ".afb") != NULL);
67 STATIC json_object *checkCardDirExit (AFB_session *session, AFB_request *request ) {
68 int sessionDir, cardDir;
70 // card name should be more than 3 character long !!!!
71 if (strlen (request->plugin) < 3) {
72 return (jsonNewMessage (AFB_FAIL,"Fail invalid plugin=%s", request->plugin));
75 // open session directory
76 sessionDir = open (session->config->sessiondir, O_DIRECTORY);
78 return (jsonNewMessage (AFB_FAIL,"Fail to open directory [%s] error=%s", session->config->sessiondir, strerror(sessionDir)));
81 // create session sndcard directory if it does not exit
82 cardDir = openat (sessionDir, request->plugin, O_DIRECTORY);
84 cardDir = mkdirat (sessionDir, request->plugin, O_RDWR | S_IRWXU | S_IRGRP);
86 return (jsonNewMessage (AFB_FAIL,"Fail to create directory [%s/%s] error=%s", session->config->sessiondir, request->plugin, strerror(cardDir)));
93 // create a session in current directory
94 PUBLIC json_object *sessionList (AFB_session *session, AFB_request *request) {
95 json_object *sessionsJ, *ajgResponse;
97 struct dirent **namelist;
98 int count, sessionDir;
100 // if directory for card's sessions does not exist create it
101 ajgResponse = checkCardDirExit (session, request);
102 if (ajgResponse != NULL) return ajgResponse;
104 // open session directory
105 sessionDir = open (session->config->sessiondir, O_DIRECTORY);
106 if (sessionDir < 0) {
107 return (jsonNewMessage (AFB_FAIL,"Fail to open directory [%s] error=%s", session->config->sessiondir, strerror(sessionDir)));
110 count = scandirat (sessionDir, request->plugin, &namelist, fileSelect, alphasort);
114 return (jsonNewMessage (AFB_FAIL,"Fail to scan sessions directory [%s/%s] error=%s", session->config->sessiondir, request->plugin, strerror(sessionDir)));
116 if (count == 0) return (jsonNewMessage (AFB_EMPTY,"[%s] no session at [%s]", request->plugin, session->config->sessiondir));
118 // loop on each session file, retrieve its date and push it into json response object
119 sessionsJ = json_object_new_array();
121 json_object *sessioninfo;
125 // extract file name and last modification date
126 filename = namelist[count]->d_name;
127 printf("%s\n", filename);
128 stat(filename,&fstat);
129 strftime (timestamp, sizeof(timestamp), "%c", localtime (&fstat.st_mtime));
130 filename[strlen(filename)-4] = '\0'; // remove .afb extension from filename
132 // create an object by session with last update date
133 sessioninfo = json_object_new_object();
134 json_object_object_add (sessioninfo, "date" , json_object_new_string (timestamp));
135 json_object_object_add (sessioninfo, "session" , json_object_new_string (filename));
136 json_object_array_add (sessionsJ, sessioninfo);
138 free(namelist[count]);
141 // free scandir structure
144 // everything is OK let's build final response
145 ajgResponse = json_object_new_object();
146 json_object_object_add (ajgResponse, "jtype" , json_object_new_string (AFB_SESSION_JLIST));
147 json_object_object_add (ajgResponse, "status" , jsonNewStatus(AFB_SUCCESS));
148 json_object_object_add (ajgResponse, "data" , sessionsJ);
150 return (ajgResponse);
153 // Create a link toward last used sessionname within sndcard directory
154 STATIC void makeSessionLink (const char *cardname, const char *sessionname) {
155 char linkname [256], filename [256];
157 // create a link to keep track of last uploaded sessionname for this card
158 strncpy (filename, sessionname, sizeof(filename));
159 strncat (filename, ".afb", sizeof(filename));
161 strncpy (linkname, cardname, sizeof(linkname));
162 strncat (linkname, "/", sizeof(filename));
163 strncat (linkname, AFB_CURRENT_SESSION, sizeof(linkname));
164 strncat (linkname, ".afb", sizeof(filename));
165 unlink (linkname); // remove previous link if any
166 err = symlink (filename, linkname);
167 if (err < 0) fprintf (stderr, "Fail to create link %s->%s error=%s\n", linkname, filename, strerror(errno));
170 // Load Json session object from disk
171 PUBLIC json_object *sessionFromDisk (AFB_session *session, AFB_request *request, char *name) {
172 json_object *jsonSession, *jtype, *response;
173 const char *ajglabel;
178 return (jsonNewMessage (AFB_FATAL,"session name missing &session=MySessionName"));
181 // check for current session request
182 defsession = (strcmp (name, AFB_DEFAULT_SESSION) ==0);
184 // if directory for card's sessions does not exist create it
185 response = checkCardDirExit (session, request);
186 if (response != NULL) return response;
188 // add name and file extension to session name
189 strncpy (filename, request->plugin, sizeof(filename));
190 strncat (filename, "/", sizeof(filename));
191 if (defsession) strncat (filename, AFB_CURRENT_SESSION, sizeof(filename)-1);
192 else strncat (filename, name, sizeof(filename)-1);
193 strncat (filename, ".afb", sizeof(filename));
195 // just upload json object and return without any further processing
196 jsonSession = json_object_from_file (filename);
198 if (jsonSession == NULL) return (jsonNewMessage (AFB_EMPTY,"File [%s] not found", filename));
200 // verify that file is a JSON ALSA session type
201 if (!json_object_object_get_ex (jsonSession, "jtype", &jtype)) {
202 json_object_put (jsonSession);
203 return (jsonNewMessage (AFB_EMPTY,"File [%s] 'jtype' descriptor not found", filename));
206 // check type value is AFB_SESSION_JTYPE
207 ajglabel = json_object_get_string (jtype);
208 if (strcmp (AFB_SESSION_JTYPE, ajglabel)) {
209 json_object_put (jsonSession);
210 return (jsonNewMessage (AFB_FATAL,"File [%s] jtype=[%s] != [%s]", filename, ajglabel, AFB_SESSION_JTYPE));
213 // create a link to keep track of last uploaded session for this card
214 if (!defsession) makeSessionLink (request->plugin, name);
216 return (jsonSession);
219 // push Json session object to disk
220 PUBLIC json_object * sessionToDisk (AFB_session *session, AFB_request *request, char *name, json_object *jsonSession) {
223 struct tm * timeinfo;
225 static json_object *response;
227 // we should have a session name
228 if (name == NULL) return (jsonNewMessage (AFB_FATAL,"session name missing &session=MySessionName"));
230 // check for current session request
231 defsession = (strcmp (name, AFB_DEFAULT_SESSION) ==0);
233 // if directory for card's sessions does not exist create it
234 response = checkCardDirExit (session, request);
235 if (response != NULL) return response;
237 // add cardname and file extension to session name
238 strncpy (filename, request->plugin, sizeof(filename));
239 strncat (filename, "/", sizeof(filename));
240 if (defsession) strncat (filename, AFB_CURRENT_SESSION, sizeof(filename)-1);
241 else strncat (filename, name, sizeof(filename)-1);
242 strncat (filename, ".afb", sizeof(filename)-1);
245 json_object_object_add(jsonSession, "jtype", json_object_new_string (AFB_SESSION_JTYPE));
247 // add a timestamp and store session on disk
248 time ( &rawtime ); timeinfo = localtime ( &rawtime );
249 // A copy of the string is made and the memory is managed by the json_object
250 json_object_object_add (jsonSession, "timestamp", json_object_new_string (asctime (timeinfo)));
253 // do we have extra session info ?
255 static json_object *info, *jtype;
256 const char *ajglabel;
258 // extract session info from args
259 info = json_tokener_parse (request->post);
261 response = jsonNewMessage (AFB_FATAL,"sndcard=%s session=%s invalid json args=%s", request->plugin, name, request->post);
265 // info is a valid AFB_info type
266 if (!json_object_object_get_ex (info, "jtype", &jtype)) {
267 response = jsonNewMessage (AFB_EMPTY,"sndcard=%s session=%s No 'AFB_type' args=%s", request->plugin, name, request->post);
271 // check type value is AFB_INFO_JTYPE
272 ajglabel = json_object_get_string (jtype);
273 if (strcmp (AFB_SESSION_JINFO, ajglabel)) {
274 json_object_put (info); // release info json object
275 response = jsonNewMessage (AFB_FATAL,"File [%s] jtype=[%s] != [%s] data=%s", filename, ajglabel, AFB_SESSION_JTYPE, request->post);
279 // this is valid info data for our session
280 json_object_object_add (jsonSession, "info", info);
283 // Finally save session on disk
284 err = json_object_to_file (filename, jsonSession);
286 response = jsonNewMessage (AFB_FATAL,"Fail save session = [%s] to disk", filename);
291 // create a link to keep track of last uploaded session for this card
292 if (!defsession) makeSessionLink (request->plugin, name);
294 // we're donne let's return status message
295 response = jsonNewMessage (AFB_SUCCESS,"Session= [%s] saved on disk", filename);
296 json_object_put (jsonSession);
300 json_object_put (jsonSession);