aboutsummaryrefslogtreecommitdiff
path: root/firebase.c
diff options
context:
space:
mode:
Diffstat (limited to 'firebase.c')
-rw-r--r--firebase.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/firebase.c b/firebase.c
new file mode 100644
index 0000000..780b973
--- /dev/null
+++ b/firebase.c
@@ -0,0 +1,136 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include "db.h"
+#include "firebase.h"
+
+
+#define JS_PLUGIN_PATH "firebase-io/firebase-io.js"
+
+FILE *js_write=NULL;
+
+
+static void write_field(FILE *f,const char *key,const char *value){
+ fprintf(f," %s %zu %s",key,strlen(value),value);
+}
+
+static void token_send(const char *token,const char *room,const char *user,const char *msg){
+ fprintf(js_write,"message");
+ write_field(js_write,"token",token);
+ write_field(js_write,"room",room);
+ write_field(js_write,"user",user);
+ write_field(js_write,"message",msg);
+ fprintf(js_write,"\n");
+ fflush(js_write);
+}
+
+static void script_output_listener(FILE *js_read){
+ // Do not use js_write here, it's NULL
+ char *line=NULL;
+ size_t linecap=0;
+ ssize_t linelen;
+ while((linelen=getline(&line,&linecap,js_read))>0){
+ if(line[linelen-1]!='\n'){
+ fprintf(stderr,"firebase thread: unexpected EOF from js script\n");
+ return;
+ }
+ line[linelen-1]='\0';
+ linelen--;
+
+ char *spacep=strchr(line,' ');
+ if(spacep==NULL)goto invalid_line;
+ *spacep='\0';
+ char *cmd=line;
+
+ if(strcmp(cmd,"add_token")==0||strcmp(cmd,"delete_token")==0){
+ char *username=spacep+1;
+ spacep=strchr(username,' ');
+ if(spacep==NULL)goto invalid_line;
+ *spacep='\0';
+ char *token=spacep+1;
+
+ i64 userid=db_find_user(username);
+ if(userid==-1){
+ fprintf(stderr,"firebase thread: unknown username '%s'\n",username);
+ continue;
+ }
+
+ if(strcmp(cmd,"add_token")==0){
+ db_add_token(userid,token);
+ } else {
+ db_delete_token(userid,token);
+ }
+ }
+
+ continue;
+
+ invalid_line:
+ fprintf(stderr,"firebase thread: Invalid line form js script: <%s>\n",line);
+ }
+}
+
+
+void firebase_init(void){
+ int wrpipe[2],rdpipe[2];
+ if(pipe(wrpipe)<0||pipe(rdpipe)<0){
+ perror("pipe");
+ exit(1);
+ }
+
+ pid_t pid=fork(); // The JS script
+ if(pid<0){
+ perror("fork");
+ exit(1);
+ }
+ if(pid==0){
+ close(wrpipe[1]);
+ close(rdpipe[0]);
+ dup2(wrpipe[0],0);
+ dup2(rdpipe[1],1);
+ execl(JS_PLUGIN_PATH,JS_PLUGIN_PATH);
+ perror("execl");
+ exit(1);
+ }
+ close(wrpipe[0]);
+ close(rdpipe[1]);
+
+ pid=fork(); // The script stdout listener
+ if(pid<0){
+ perror("fork");
+ exit(1);
+ }
+ if(pid==0){
+ close(wrpipe[1]);
+ FILE *js_read=fdopen(rdpipe[0],"r");
+ script_output_listener(js_read);
+ fclose(js_read);
+ exit(0);
+ }
+
+ js_write=fdopen(wrpipe[1],"w");
+ printf("Started js firebase plugin\n");
+}
+
+void firebase_stop(void){
+ // Script will stop itself on EOF on stdin
+ fclose(js_write);
+}
+
+void firebase_send_message(const char *room,i64 roomid,const char *user,const char *msg){
+ if(roomid==-1)roomid=db_find_room(room);
+ if(roomid==-1){
+ debug("firebase_send_message: Cannot find roomid for room '%s'",room);
+ return;
+ }
+
+ struct db_user_list members=db_list_members(roomid);
+ for(i64 i=0;i<members.count;i++){
+ struct db_strings_list tokens=db_user_tokens(members.list[i].id);
+ for(i64 j=0;j<tokens.count;j++){
+ token_send(tokens.list[j],room,user,msg);
+ }
+ db_nullify_strings_list(tokens);
+ }
+ db_nullify_user_list(members);
+}