Initial import
This commit is contained in:
		
							
								
								
									
										5
									
								
								.firebaserc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								.firebaserc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | |||||||
|  | { | ||||||
|  |   "projects": { | ||||||
|  |     "default": "ha-client-c73c4" | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										65
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,65 @@ | |||||||
|  | # Logs | ||||||
|  | logs | ||||||
|  | *.log | ||||||
|  | npm-debug.log* | ||||||
|  | yarn-debug.log* | ||||||
|  | yarn-error.log* | ||||||
|  | firebase-debug.log* | ||||||
|  |  | ||||||
|  | # Firebase cache | ||||||
|  | .firebase/ | ||||||
|  |  | ||||||
|  | # Firebase config | ||||||
|  |  | ||||||
|  | # Uncomment this if you'd like others to create their own Firebase project. | ||||||
|  | # For a team working on the same Firebase project(s), it is recommended to leave | ||||||
|  | # it commented so all members can deploy to the same project(s) in .firebaserc. | ||||||
|  | # .firebaserc | ||||||
|  |  | ||||||
|  | # Runtime data | ||||||
|  | pids | ||||||
|  | *.pid | ||||||
|  | *.seed | ||||||
|  | *.pid.lock | ||||||
|  |  | ||||||
|  | # Directory for instrumented libs generated by jscoverage/JSCover | ||||||
|  | lib-cov | ||||||
|  |  | ||||||
|  | # Coverage directory used by tools like istanbul | ||||||
|  | coverage | ||||||
|  |  | ||||||
|  | # nyc test coverage | ||||||
|  | .nyc_output | ||||||
|  |  | ||||||
|  | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||||||
|  | .grunt | ||||||
|  |  | ||||||
|  | # Bower dependency directory (https://bower.io/) | ||||||
|  | bower_components | ||||||
|  |  | ||||||
|  | # node-waf configuration | ||||||
|  | .lock-wscript | ||||||
|  |  | ||||||
|  | # Compiled binary addons (http://nodejs.org/api/addons.html) | ||||||
|  | build/Release | ||||||
|  |  | ||||||
|  | # Dependency directories | ||||||
|  | node_modules/ | ||||||
|  |  | ||||||
|  | # Optional npm cache directory | ||||||
|  | .npm | ||||||
|  |  | ||||||
|  | # Optional eslint cache | ||||||
|  | .eslintcache | ||||||
|  |  | ||||||
|  | # Optional REPL history | ||||||
|  | .node_repl_history | ||||||
|  |  | ||||||
|  | # Output of 'npm pack' | ||||||
|  | *.tgz | ||||||
|  |  | ||||||
|  | # Yarn Integrity file | ||||||
|  | .yarn-integrity | ||||||
|  |  | ||||||
|  | # dotenv environment variables file | ||||||
|  | .env | ||||||
							
								
								
									
										1
									
								
								firebase.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								firebase.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | {} | ||||||
							
								
								
									
										1
									
								
								functions/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								functions/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | node_modules/ | ||||||
							
								
								
									
										153
									
								
								functions/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								functions/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  | 'use strict'; | ||||||
|  |  | ||||||
|  | const functions = require('firebase-functions'); | ||||||
|  | const admin = require('firebase-admin'); | ||||||
|  | admin.initializeApp(); | ||||||
|  |  | ||||||
|  | var db = admin.firestore(); | ||||||
|  |  | ||||||
|  | const MAX_NOTIFICATIONS_PER_DAY = 150; | ||||||
|  |  | ||||||
|  | exports.sendPushNotification = functions.https.onRequest(async (req, res) => { | ||||||
|  |   console.log('Received payload', req.body); | ||||||
|  |   var today = getToday(); | ||||||
|  |   var token = req.body.push_token; | ||||||
|  |   var ref = db.collection('rateLimits').doc(today).collection('tokens').doc(token); | ||||||
|  |  | ||||||
|  |   var payload = { | ||||||
|  |     notification: { | ||||||
|  |       body: req.body.message | ||||||
|  |     }, | ||||||
|  |     android: { | ||||||
|  |         priority: 'HIGH', | ||||||
|  |         notification: { | ||||||
|  |             sound: 'default', | ||||||
|  |             icon: 'mini_icon', | ||||||
|  |             channel_id: 'ha_notify' | ||||||
|  |         } | ||||||
|  |     }, | ||||||
|  |     token: token, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   if(req.body.title) { | ||||||
|  |     payload.notification.title = req.body.title; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(req.body.data) { | ||||||
|  |     if(req.body.data.android) { | ||||||
|  |       payload.android = req.body.data.android; | ||||||
|  |     } | ||||||
|  |     if(req.body.data.apns) { | ||||||
|  |       payload.apns = req.body.data.apns; | ||||||
|  |     } | ||||||
|  |     if(req.body.data.data) { | ||||||
|  |       payload.data = req.body.data.data; | ||||||
|  |     } | ||||||
|  |     if(req.body.data.webpush) { | ||||||
|  |       payload.webpush = req.body.data.webpush; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   console.log('Notification payload', JSON.stringify(payload)); | ||||||
|  |  | ||||||
|  |   var docExists = false; | ||||||
|  |   var docData = { | ||||||
|  |     deliveredCount: 0, | ||||||
|  |     errorCount: 0, | ||||||
|  |     totalCount: 0, | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   try { | ||||||
|  |     let currentDoc = await ref.get(); | ||||||
|  |     docExists = currentDoc.exists; | ||||||
|  |     if(currentDoc.exists) { | ||||||
|  |       docData = currentDoc.data(); | ||||||
|  |     } | ||||||
|  |   } catch(err) { | ||||||
|  |     console.error('Error getting document!', err); | ||||||
|  |     return handleError(res, 'getDoc', err); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if(docData.deliveredCount > MAX_NOTIFICATIONS_PER_DAY) { | ||||||
|  |     return res.status(429).send({ | ||||||
|  |       errorType: 'RateLimited', | ||||||
|  |       message: 'The given target has reached the maximum number of notifications allowed per day. Please try again later.', | ||||||
|  |       target: token, | ||||||
|  |       rateLimits: getRateLimitsObject(docData), | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   docData.totalCount = docData.totalCount + 1; | ||||||
|  |  | ||||||
|  |   var messageId; | ||||||
|  |   try { | ||||||
|  |     messageId = await admin.messaging().send(payload); | ||||||
|  |     docData.deliveredCount = docData.deliveredCount + 1; | ||||||
|  |   } catch(err) { | ||||||
|  |     docData.errorCount = docData.errorCount + 1; | ||||||
|  |     await setRateLimitDoc(ref, docExists, docData, res); | ||||||
|  |     return handleError(res, 'sendNotification', err); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   console.log('Successfully sent message:', messageId); | ||||||
|  |  | ||||||
|  |   await setRateLimitDoc(ref, docExists, docData, res); | ||||||
|  |  | ||||||
|  |   return res.status(201).send({ | ||||||
|  |     messageId: messageId, | ||||||
|  |     sentPayload: payload, | ||||||
|  |     target: token, | ||||||
|  |     rateLimits: getRateLimitsObject(docData), | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | async function setRateLimitDoc(ref, docExists, docData, res) { | ||||||
|  |   try { | ||||||
|  |     if(docExists) { | ||||||
|  |       console.log('Updating existing doc!'); | ||||||
|  |       await ref.update(docData); | ||||||
|  |     } else { | ||||||
|  |       console.log('Creating new doc!'); | ||||||
|  |       await ref.set(docData); | ||||||
|  |     } | ||||||
|  |   } catch(err) { | ||||||
|  |     if(docExists) { | ||||||
|  |       console.error('Error updating document!', err); | ||||||
|  |     } else { | ||||||
|  |       console.error('Error creating document!', err); | ||||||
|  |     } | ||||||
|  |     return handleError(res, 'setDocument', err); | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function handleError(res, step, incomingError) { | ||||||
|  |   if (!incomingError) return null; | ||||||
|  |   console.error('InternalError during', step, incomingError); | ||||||
|  |   return res.status(500).send({ | ||||||
|  |     errorType: 'InternalError', | ||||||
|  |     errorStep: step, | ||||||
|  |     message: incomingError.message, | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getToday() { | ||||||
|  |   var today = new Date(); | ||||||
|  |   var dd = String(today.getDate()).padStart(2, '0'); | ||||||
|  |   var mm = String(today.getMonth() + 1).padStart(2, '0'); | ||||||
|  |   var yyyy = today.getFullYear(); | ||||||
|  |   return yyyy + mm + dd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function getRateLimitsObject(doc) { | ||||||
|  |   var d = new Date(); | ||||||
|  |   return { | ||||||
|  |     successful: (doc.deliveredCount || 0), | ||||||
|  |     errors: (doc.errorCount || 0), | ||||||
|  |     total: (doc.totalCount || 0), | ||||||
|  |     maximum: MAX_NOTIFICATIONS_PER_DAY, | ||||||
|  |     remaining: (MAX_NOTIFICATIONS_PER_DAY - doc.deliveredCount), | ||||||
|  |     resetsAt: new Date(d.getFullYear(), d.getMonth(), d.getDate()+1) | ||||||
|  |   }; | ||||||
|  | } | ||||||
							
								
								
									
										2008
									
								
								functions/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										2008
									
								
								functions/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										22
									
								
								functions/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								functions/package.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | { | ||||||
|  |   "name": "functions", | ||||||
|  |   "description": "Cloud Functions for Firebase", | ||||||
|  |   "scripts": { | ||||||
|  |     "serve": "firebase serve --only functions", | ||||||
|  |     "shell": "firebase functions:shell", | ||||||
|  |     "start": "npm run shell", | ||||||
|  |     "deploy": "firebase deploy --only functions", | ||||||
|  |     "logs": "firebase functions:log" | ||||||
|  |   }, | ||||||
|  |   "engines": { | ||||||
|  |     "node": "8" | ||||||
|  |   }, | ||||||
|  |   "dependencies": { | ||||||
|  |     "firebase-admin": "^8.0.0", | ||||||
|  |     "firebase-functions": "^3.0.0" | ||||||
|  |   }, | ||||||
|  |   "devDependencies": { | ||||||
|  |     "firebase-functions-test": "^0.1.6" | ||||||
|  |   }, | ||||||
|  |   "private": true | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | { | ||||||
|  |   "lockfileVersion": 1 | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user