#include #include #include #include #include #include "db.h" #include "firebase.h" #include "user_data.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 *to_user,const char *room,const char *user,const char *msg){ fprintf(stderr,"token_send(%s,%s,%s,%s,%s)\n",token,to_user,room,user,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,"to_user",to_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(true){ linelen=getline(&line,&linecap,js_read); if(linelen<0){ if(errno==EINTR)continue; break; } 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){ fprintf(stderr,"firebase thread: adding token '%s' to %" PRIi64 "\n",token,userid); db_add_token(userid,token); } else { fprintf(stderr,"firebase thread: deleting token '%s' from %" PRIi64 "\n",token,userid); db_delete_token(userid,token); } } continue; invalid_line: fprintf(stderr,"firebase thread: Invalid line from js script: <%s>\n",line); } if(linelen<0){ if(feof(js_read)){ fprintf(stderr,"firebase thread: feof(js_read)\n"); } else { fprintf(stderr,"firebase thread: getline: errno = %d (%s)\n",errno,strerror(errno)); } } } 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,NULL); 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"); db_reinit(); 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){ if(js_write){ // Script will stop itself on EOF on stdin fclose(js_write); js_write=NULL; } } void firebase_send_message(const char *room,i64 roomid,const char *user,const char *msg){ // If not initialised, do nothing if(!js_write)return; 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