summaryrefslogtreecommitdiffstats
path: root/src/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/session.c')
-rw-r--r--src/session.c302
1 files changed, 302 insertions, 0 deletions
diff --git a/src/session.c b/src/session.c
new file mode 100644
index 00000000..2bb5b442
--- /dev/null
+++ b/src/session.c
@@ -0,0 +1,302 @@
+/*
+ * Copyright (C) 2015 "IoT.bzh"
+ * Author "Fulup Ar Foll"
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "local-def.h"
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define AFB_SESSION_JTYPE "AFB_session"
+#define AFB_SESSION_JLIST "AFB_sessions"
+#define AFB_SESSION_JINFO "AFB_infos"
+
+#define AFB_CURRENT_SESSION "active-session" // file link name within sndcard dir
+#define AFB_DEFAULT_SESSION "current-session" // should be in sync with UI
+
+
+
+
+// verify we can read/write in session dir
+PUBLIC AFB_ERROR sessionCheckdir (AFB_session *session) {
+
+ int err;
+
+ // in case session dir would not exist create one
+ if (verbose) fprintf (stderr, "AFB:notice checking session dir [%s]\n", session->config->sessiondir);
+ mkdir(session->config->sessiondir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+
+ // change for session directory
+ err = chdir(session->config->sessiondir);
+ if (err) {
+ fprintf(stderr,"AFB: Fail to chdir to %s error=%s\n", session->config->sessiondir, strerror(err));
+ return err;
+ }
+
+ // verify we can write session in directory
+ json_object *dummy= json_object_new_object();
+ json_object_object_add (dummy, "checked" , json_object_new_int (getppid()));
+ err = json_object_to_file ("./AFB-probe.json", dummy);
+ if (err < 0) return err;
+
+ return AFB_SUCCESS;
+}
+
+// let's return only sessions files
+STATIC int fileSelect (const struct dirent *entry) {
+ return (strstr (entry->d_name, ".afb") != NULL);
+}
+
+STATIC json_object *checkCardDirExit (AFB_session *session, AFB_request *request ) {
+ int sessionDir, cardDir;
+
+ // card name should be more than 3 character long !!!!
+ if (strlen (request->plugin) < 3) {
+ return (jsonNewMessage (AFB_FAIL,"Fail invalid plugin=%s", request->plugin));
+ }
+
+ // open session directory
+ sessionDir = open (session->config->sessiondir, O_DIRECTORY);
+ if (sessionDir < 0) {
+ return (jsonNewMessage (AFB_FAIL,"Fail to open directory [%s] error=%s", session->config->sessiondir, strerror(sessionDir)));
+ }
+
+ // create session sndcard directory if it does not exit
+ cardDir = openat (sessionDir, request->plugin, O_DIRECTORY);
+ if (cardDir < 0) {
+ cardDir = mkdirat (sessionDir, request->plugin, O_RDWR | S_IRWXU | S_IRGRP);
+ if (cardDir < 0) {
+ return (jsonNewMessage (AFB_FAIL,"Fail to create directory [%s/%s] error=%s", session->config->sessiondir, request->plugin, strerror(cardDir)));
+ }
+ }
+ close (sessionDir);
+ return NULL;
+}
+
+// create a session in current directory
+PUBLIC json_object *sessionList (AFB_session *session, AFB_request *request) {
+ json_object *sessionsJ, *ajgResponse;
+ struct stat fstat;
+ struct dirent **namelist;
+ int count, sessionDir;
+
+ // if directory for card's sessions does not exist create it
+ ajgResponse = checkCardDirExit (session, request);
+ if (ajgResponse != NULL) return ajgResponse;
+
+ // open session directory
+ sessionDir = open (session->config->sessiondir, O_DIRECTORY);
+ if (sessionDir < 0) {
+ return (jsonNewMessage (AFB_FAIL,"Fail to open directory [%s] error=%s", session->config->sessiondir, strerror(sessionDir)));
+ }
+
+ count = scandirat (sessionDir, request->plugin, &namelist, fileSelect, alphasort);
+ close (sessionDir);
+
+ if (count < 0) {
+ return (jsonNewMessage (AFB_FAIL,"Fail to scan sessions directory [%s/%s] error=%s", session->config->sessiondir, request->plugin, strerror(sessionDir)));
+ }
+ if (count == 0) return (jsonNewMessage (AFB_EMPTY,"[%s] no session at [%s]", request->plugin, session->config->sessiondir));
+
+ // loop on each session file, retrieve its date and push it into json response object
+ sessionsJ = json_object_new_array();
+ while (count--) {
+ json_object *sessioninfo;
+ char timestamp [64];
+ char *filename;
+
+ // extract file name and last modification date
+ filename = namelist[count]->d_name;
+ printf("%s\n", filename);
+ stat(filename,&fstat);
+ strftime (timestamp, sizeof(timestamp), "%c", localtime (&fstat.st_mtime));
+ filename[strlen(filename)-4] = '\0'; // remove .afb extension from filename
+
+ // create an object by session with last update date
+ sessioninfo = json_object_new_object();
+ json_object_object_add (sessioninfo, "date" , json_object_new_string (timestamp));
+ json_object_object_add (sessioninfo, "session" , json_object_new_string (filename));
+ json_object_array_add (sessionsJ, sessioninfo);
+
+ free(namelist[count]);
+ }
+
+ // free scandir structure
+ free(namelist);
+
+ // everything is OK let's build final response
+ ajgResponse = json_object_new_object();
+ json_object_object_add (ajgResponse, "jtype" , json_object_new_string (AFB_SESSION_JLIST));
+ json_object_object_add (ajgResponse, "status" , jsonNewStatus(AFB_SUCCESS));
+ json_object_object_add (ajgResponse, "data" , sessionsJ);
+
+ return (ajgResponse);
+}
+
+// Create a link toward last used sessionname within sndcard directory
+STATIC void makeSessionLink (const char *cardname, const char *sessionname) {
+ char linkname [256], filename [256];
+ int err;
+ // create a link to keep track of last uploaded sessionname for this card
+ strncpy (filename, sessionname, sizeof(filename));
+ strncat (filename, ".afb", sizeof(filename));
+
+ strncpy (linkname, cardname, sizeof(linkname));
+ strncat (linkname, "/", sizeof(filename));
+ strncat (linkname, AFB_CURRENT_SESSION, sizeof(linkname));
+ strncat (linkname, ".afb", sizeof(filename));
+ unlink (linkname); // remove previous link if any
+ err = symlink (filename, linkname);
+ if (err < 0) fprintf (stderr, "Fail to create link %s->%s error=%s\n", linkname, filename, strerror(errno));
+}
+
+// Load Json session object from disk
+PUBLIC json_object *sessionFromDisk (AFB_session *session, AFB_request *request, char *name) {
+ json_object *jsonSession, *jtype, *response;
+ const char *ajglabel;
+ char filename [256];
+ int defsession;
+
+ if (name == NULL) {
+ return (jsonNewMessage (AFB_FATAL,"session name missing &session=MySessionName"));
+ }
+
+ // check for current session request
+ defsession = (strcmp (name, AFB_DEFAULT_SESSION) ==0);
+
+ // if directory for card's sessions does not exist create it
+ response = checkCardDirExit (session, request);
+ if (response != NULL) return response;
+
+ // add name and file extension to session name
+ strncpy (filename, request->plugin, sizeof(filename));
+ strncat (filename, "/", sizeof(filename));
+ if (defsession) strncat (filename, AFB_CURRENT_SESSION, sizeof(filename)-1);
+ else strncat (filename, name, sizeof(filename)-1);
+ strncat (filename, ".afb", sizeof(filename));
+
+ // just upload json object and return without any further processing
+ jsonSession = json_object_from_file (filename);
+
+ if (jsonSession == NULL) return (jsonNewMessage (AFB_EMPTY,"File [%s] not found", filename));
+
+ // verify that file is a JSON ALSA session type
+ if (!json_object_object_get_ex (jsonSession, "jtype", &jtype)) {
+ json_object_put (jsonSession);
+ return (jsonNewMessage (AFB_EMPTY,"File [%s] 'jtype' descriptor not found", filename));
+ }
+
+ // check type value is AFB_SESSION_JTYPE
+ ajglabel = json_object_get_string (jtype);
+ if (strcmp (AFB_SESSION_JTYPE, ajglabel)) {
+ json_object_put (jsonSession);
+ return (jsonNewMessage (AFB_FATAL,"File [%s] jtype=[%s] != [%s]", filename, ajglabel, AFB_SESSION_JTYPE));
+ }
+
+ // create a link to keep track of last uploaded session for this card
+ if (!defsession) makeSessionLink (request->plugin, name);
+
+ return (jsonSession);
+}
+
+// push Json session object to disk
+PUBLIC json_object * sessionToDisk (AFB_session *session, AFB_request *request, char *name, json_object *jsonSession) {
+ char filename [256];
+ time_t rawtime;
+ struct tm * timeinfo;
+ int err, defsession;
+ static json_object *response;
+
+ // we should have a session name
+ if (name == NULL) return (jsonNewMessage (AFB_FATAL,"session name missing &session=MySessionName"));
+
+ // check for current session request
+ defsession = (strcmp (name, AFB_DEFAULT_SESSION) ==0);
+
+ // if directory for card's sessions does not exist create it
+ response = checkCardDirExit (session, request);
+ if (response != NULL) return response;
+
+ // add cardname and file extension to session name
+ strncpy (filename, request->plugin, sizeof(filename));
+ strncat (filename, "/", sizeof(filename));
+ if (defsession) strncat (filename, AFB_CURRENT_SESSION, sizeof(filename)-1);
+ else strncat (filename, name, sizeof(filename)-1);
+ strncat (filename, ".afb", sizeof(filename)-1);
+
+
+ json_object_object_add(jsonSession, "jtype", json_object_new_string (AFB_SESSION_JTYPE));
+
+ // add a timestamp and store session on disk
+ time ( &rawtime ); timeinfo = localtime ( &rawtime );
+ // A copy of the string is made and the memory is managed by the json_object
+ json_object_object_add (jsonSession, "timestamp", json_object_new_string (asctime (timeinfo)));
+
+
+ // do we have extra session info ?
+ if (request->post) {
+ static json_object *info, *jtype;
+ const char *ajglabel;
+
+ // extract session info from args
+ info = json_tokener_parse (request->post);
+ if (!info) {
+ response = jsonNewMessage (AFB_FATAL,"sndcard=%s session=%s invalid json args=%s", request->plugin, name, request->post);
+ goto OnErrorExit;
+ }
+
+ // info is a valid AFB_info type
+ if (!json_object_object_get_ex (info, "jtype", &jtype)) {
+ response = jsonNewMessage (AFB_EMPTY,"sndcard=%s session=%s No 'AFB_type' args=%s", request->plugin, name, request->post);
+ goto OnErrorExit;
+ }
+
+ // check type value is AFB_INFO_JTYPE
+ ajglabel = json_object_get_string (jtype);
+ if (strcmp (AFB_SESSION_JINFO, ajglabel)) {
+ json_object_put (info); // release info json object
+ response = jsonNewMessage (AFB_FATAL,"File [%s] jtype=[%s] != [%s] data=%s", filename, ajglabel, AFB_SESSION_JTYPE, request->post);
+ goto OnErrorExit;
+ }
+
+ // this is valid info data for our session
+ json_object_object_add (jsonSession, "info", info);
+ }
+
+ // Finally save session on disk
+ err = json_object_to_file (filename, jsonSession);
+ if (err < 0) {
+ response = jsonNewMessage (AFB_FATAL,"Fail save session = [%s] to disk", filename);
+ goto OnErrorExit;
+ }
+
+
+ // create a link to keep track of last uploaded session for this card
+ if (!defsession) makeSessionLink (request->plugin, name);
+
+ // we're donne let's return status message
+ response = jsonNewMessage (AFB_SUCCESS,"Session= [%s] saved on disk", filename);
+ json_object_put (jsonSession);
+ return (response);
+
+OnErrorExit:
+ json_object_put (jsonSession);
+ return response;
+}