aboutsummaryrefslogtreecommitdiff
path: root/firebase-io/firebase-io.js
diff options
context:
space:
mode:
Diffstat (limited to 'firebase-io/firebase-io.js')
-rwxr-xr-xfirebase-io/firebase-io.js134
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!");