diff options
Diffstat (limited to 'firebase-io/firebase-io.js')
-rwxr-xr-x | firebase-io/firebase-io.js | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/firebase-io/firebase-io.js b/firebase-io/firebase-io.js new file mode 100755 index 0000000..8a94076 --- /dev/null +++ b/firebase-io/firebase-io.js @@ -0,0 +1,134 @@ +#!/usr/bin/env node +const firebase=require("firebase-admin"); +const util=require("util"); + +firebase.initializeApp({ + credential:firebase.credential.cert(require("./firebaseServiceAccountKey.json")), + databaseURL:"https://tomsg-83196.firebaseio.com", +}); + +const fieldConverters=new Map([ + ["token",(b)=>b.toString()], + ["user",(b)=>b.toString()], + ["room",(b)=>b.toString()], + ["message",(b)=>b.toString()], + ["timestamp",(b)=>b.toString()], // Nanosecond timestamps are too close to 52-bit range + ["online",(b)=>parseInt(b.toString(),10)], +]); + +function typeConvertFields(fields){ + for(const key of fields.keys()){ + const conv=fieldConverters.get(key); + if(conv!=undefined)fields.set(key,conv(fields.get(key))); + } +} + +function readFields(buffer){ + const fields=new Map(); + if(buffer.length==0)return fields; + let cursor=0; + while(true){ + let idx=buffer.indexOf(32,cursor); + if(idx==-1){ + console.error("ERR: Incomplete field in input line"); + return null; + } + const key=String(buffer.slice(cursor,idx)); + cursor=idx+1; + + idx=buffer.indexOf(32,cursor); + if(idx==-1){ + console.error("ERR: Incomplete field in input line"); + return null; + } + const arglen=parseInt(String(buffer.slice(cursor,idx)),10); + if(arglen<0||arglen==null||isNaN(arglen)){ + console.error("ERR: Invalid length in input line"); + return null; + } + cursor=idx+1; + + if(cursor+arglen>buffer.length){ + console.error("ERR: Length larger than remaining line in input line"); + return null; + } + const arg=buffer.slice(cursor,cursor+arglen); + cursor+=arglen; + + fields.set(key,arg); + + if(cursor==buffer.length)break; + if(buffer[cursor]!=32){ + console.error("ERR: No space after argument in input line"); + return null; + } + cursor++; + } + return fields; +} + +function processMessage(type,fields){ + switch(type){ + case "message": + const user=fields.get("user"); + const token=fields.get("token"); + const payload={ + notification: { + title: user+" ("+fields.get("room")+")", + body: fields.get("message"), + } + }; + firebase.messaging().sendToDevice(token,payload) + .then((response)=>{ + const result=response.results[0]; + const realToken=result.canonicalRegistrationToken; + if(result.error){ + console.error("JS: Send error:",result.error); + } else if(realToken&&realToken!=token){ + console.log("delete_token "+user+" "+token); + console.log("add_token "+user+" "+realToken); + } + }) + .catch((err)=>{ + console.error("JS: Early send error:",err); + }); + break; + + default: + console.error("JS: Unknown type '"+type+"'"); + } +} + +function handleInputLine(buffer){ + let idx=buffer.indexOf(32); + if(idx==-1){ + console.error("ERR: No space in input line"); + return; + } + const type=String(buffer.slice(0,idx)); + const fields=readFields(buffer.slice(idx+1)); + if(fields==null)return; + typeConvertFields(fields); + processMessage(type,fields); +} + + +{ + let buffer=null; + process.stdin.on("data",(data)=>{ + const prevlen=buffer==null?0:buffer.length; + if(buffer)buffer=Buffer.concat([buffer,data]); + else buffer=data; + let cursor=0; + let lfidx=buffer.indexOf(10,prevlen); + while(lfidx!=-1){ + handleInputLine(buffer.slice(cursor,lfidx)); + cursor=lfidx+1; + lfidx=buffer.indexOf(10,cursor); + } + if(cursor>=buffer.length)buffer=null; + else buffer=Buffer.from(buffer.slice(cursor)); + }); +} + +console.error("Firebase js plugin loaded!"); |