Integrate Firebase with 3rd party API - firebase

I'd like to integrate my firebase project with some 3rd party API's, like the twitter API.
3rd party API
The following code will listen to new tweets containing the certain text 'little rocket man':
var Twitter = require('twitter');
// setup new twitter client
var client = new Twitter({
consumer_key: '',
consumer_secret: '',
access_token_key: '',
access_token_secret: ''
});
// open new twitter stream
let stream = this.client.stream('statuses/filter', { track: 'little rocket man' });
stream.on('data', (event: any) => {
let tweetText = event && event.text; // this should be written to the firebase db
});
Firebase Cloud Functions
The following firebase cloud functions listens to incoming HTTP GET requests on a specific route and saves data back to the firebase db:
import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin'; // Firebase Admin SDK
admin.initializeApp(functions.config().firebase);
// this example uses a HTTP trigger, but how can I trigger it whenever new tweets containint 'little rocket man' are detected??
exports.addMessage = functions.https.onRequest((req, res) => {
const original = req.query.text;
admin.database().ref('/messages').push({original: original}).then(snapshot => {
res.redirect(303, snapshot.ref);
});
});
Question
How can I write the tweets I'm recieving from the twitter client back to the firebase db? If possible, I'd like to run all the code on firebase cloud functions.
Disclaimer:
I'm new to firebase and although googling around for a few hours I wasn't able to find the solution to my problem on the net. I'd like to apologize in advance, should I have overseen it.

You can't use streaming APIs like this in Cloud Functions. A function may only respond to some distinct event, such as an HTTP request, or some change in your database. Functions can't run indefinitely.
If you want to collect tweets that match some query into your database, you can use IFTTT to periodically send them to a function as they become available. I recently finished a small project that does exactly that.

Related

How can scheduled Firebase Cloud Messaging notifications be made outside of the Firebase Console?

Inside the Firebase Console, under the Cloud Messaging view, users are able to create test notifications. This functionality also allows you to schedule the time at which the notification will send to a device or set of devices.
Is it possible to create and send scheduled FCM notifications to specific devices by using firebase cloud functions and the Firebase Admin SDK? Is there an alternative way to solving this?
The current way that I send scheduled messages to users is like so:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const schedule = require('node-schedule');
admin.initializeApp();
exports.setScheduledNotification = functions.https.onRequest(async (req, res) => {
const key = req.query.notification_key;
const message = {
notification: {
title: 'Test Notification',
body: 'Test Notification body.'
}
};
var currentDate = new Date();
var laterDate = new Date(currentDate.getTime() + (1 * 60000));
var job = schedule.scheduleJob(key, laterDate, () => {
const snapshot = admin.messaging().sendToDevice(key, message);
});
return res.status(200).send(`Message has been scheduled.`);
});
First of all, I am unsure how node-schedule interacts with firebase cloud functions. The logs appear that the function terminates very quickly which I would think would be correct. The longer the operation runs the more costly it is in our firebase bills. The notification does still run on a scheduled time though. I'm confused on how that all is working behind the scenes.
Secondly, I am having issues canceling these scheduled notifications. The notifications will most likely be on a 2hr timed schedule from the point it gets created. Before the 2hrs is up, I'd like the have the ability to cancel/overwrite the notification with an updated scheduled time.
I tried this to cancel the notification and it failed to find the previously created notification. Here is the code for that:
exports.cancelScheduledNotification = functions.https.onRequest(async (req, res) => {
const key = req.query.notification_key;
var job = schedule.scheduledJobs[key];
job.cancel();
return res.status(200).send(`Message has been canceled.`);
});
Is it possible to tap into the scheduling functionality of firebase cloud messaging outside of the firebase console? Or am I stuck with hacking my way around this issue?
A Cloud Function can run for a maximum of 9 minutes. So unless you're using node-schedule for periods shorter than that, your current approach won't work. Even if it would work, or if you are scheduling for less than 9 minutes in advance, using this approach is very uneconomic as you'll be paying for the Cloud Functions for all this time while it's waiting.
A more common approach is to store information about what message you want to be delivered to whom at what time in a database, and then use regular scheduled functions to periodically check what messages to send. For more on this, see these previous questions:
Firebase scheduled notification in android
How to schedule push notifcations for react native expo?
Schedule jobs in Firebase
Ionic: Is it possible to delay incoming push FCM push notification from showing to my device until a specific time
Cloud Functions for Firebase trigger on time?
How to create cron jobs dynamically in firebase
A recent improvement on this is to use the Cloud Tasks API to programmatically schedule Cloud Functions to be called at a specific time with a specific payload, and then use that to send the message through FCM. Doug Stevenson wrote a great blog post about this here: How to schedule a Cloud Function to run in the future with Cloud Tasks (to build a Firestore document TTL). While the post is about deleting documents at a certain time, you can combine it with the previous approach to schedule FCM messages too.
Scheduling of tasks is now also described in the documentation on enqueueing functions with Cloud Tasks
A final option, and one I'd actually recommend nowadays, is to separate the delivery of the message from the display of the notification.
Display of data messages (unlike notification messages) is never handled by the system, and always left to your application. So you can deliver the FCM data message straight away that then contains the time to display the message, and then wake the device up to display the message (often called a local notification) at that time.
To make Frank's answer more tangible, I am including some sample code below for scheduled cloud functions, that can help you achieve the 'scheduled FCM notifications'.
You should store the information required to send your notification(s) in Firestore (e.g. the when-to-notify parameter and the FCM token(s) of the users you want to send the notification to) and run a cloud function every minute to evaluate if there is any notification that needs to be delivered.
The function checks what Firestore documents have a WhenToNofity parameter that is due, and send the notifications to the receiver tokens immediately. Once sent, the function sets the boolean 'notificationSent' to true, to avoid that the users receive the same notification again on the next iteration.
The code below achieves just that:
const admin = require('firebase-admin');
admin.initializeApp();
const database = admin.firestore();
exports.sendNotification = functions.pubsub.schedule('* * * * *').onRun(async (context) => {
//check whether notification should be sent
//send it if yes
const query = await database.collection("experiences")
.where("whenToNotify", '<=', admin.firestore.Timestamp.now())
.where("notificationSent", "==", false).get();
query.forEach(async snapshot => {
sendNotification(snapshot.data().tokens);
await database.doc('experiences/' + snapshot.id).update({
"notificationSent": true,
});
});
function sendNotification(tokens) {
let title = "INSERT YOUR TITLE";
let body = "INSERT YOUR BODY";
const message = {
notification: { title: title, body: body},
tokens: tokens,
android: {
notification: {
sound: "default"
}
},
apns: {
payload: {
aps: {
sound: "default"
}
}
}
};
admin.messaging().sendMulticast(message).then(response => {
return console.log("Successful Message Sent");
}).catch(error => {
console.log(error);
return console.log("Error Sending Message");
});
}
return console.log('End Of Function');
});
If you're unfamiliar with setting up cloud functions, you can check how to set them up here. Cloud functions require a billing account, but you get 1M cloud invocations per month for free, which is more than enough to cover the costs of this approach.
Once done, you can insert your function in the index.js file.

How to use Telegraf (Telegram) in Firebase?

I'm trying use Telegraf library with Firebase Functions but it's not working as I expected.
I follow these this article and instructions as appear in webhooks (as appears for express example) and webhookcallback as appear in telegraf docs.
const Telegraf = require('telegraf')
// The Cloud Functions for Firebase SDK to create Cloud Functions and setup triggers.
const functions = require('firebase-functions')
// The Firebase Admin SDK to access the Firebase Realtime or Firestore Database.
const admin = require('firebase-admin')
// set telegraf and responses.
const BOT_TOKEN = 'my-telegram-bot-token'
const bot = new Telegraf(BOT_TOKEN)
bot.start((ctx) => ctx.reply("Start instructions"))
bot.help((ctx) => ctx.reply("This is help"))
bot.hears('hi', (ctx) => ctx.reply('Hola'))
bot.on('text', (ctx) => ctx.reply('Response to any text'))
bot.catch((err, ctx) => {
console.log(`Ooops, ecountered an error for ${ctx.updateType}`, err)
})
// initialize bot
bot.launch() // <-- (2)
//appends middleware
exports.ideas2coolBot = functions.https.onRequest(bot.webhookCallback(`/my-path`));
In firebase server I need add bot.launch() (2) to get worked, but it works just for max timeout set in Firebase Function. I need to recall Telegram "setWebhook" API to get work again and it works for the same time. It's like it's generate one function instance and shut down when time is over.
I noted the telegraf.launch() have options to start in poll or webhook mode but its not pretty clear for me how to use this options.
How should I use telegram.launch() to get worked in webhook mode in Firebase?
Edit:
When I used getWebhookInfo I get this result:
{
"ok": true,
"result": {
"url": "https://0dbee201.ngrok.io/test-app-project/us-central1/testAppFunction/bot",
"has_custom_certificate": false,
"pending_update_count": 7,
"last_error_date": 1573053003,
"last_error_message": "Read timeout expired",
"max_connections": 40
}
}
and console shows incoming conection but do nothing...
i functions: Beginning execution of "ideas2coolBot"
i functions: Finished "ideas2coolBot" in ~1s
Edit2:
I've been trying adding Express too...
app.use(bot.webhookCallback('/bot'))
app.get('/', (req, res) => {
res.send('Hello World from Firebase!')
})
exports.ideas2coolBot = functions.https.onRequest(app);
it's works '/' path but got nothing with '/bot'. POST to '/bot' not response.
By the way, I tried a express standalone version and works prefect, but using it with firebase doesn't respond ("Read timeout expired").
delete
bot.launch()
try add this
exports.YOURFUNCTIONNAME = functions.https.onRequest(
(req, res) => bot.handleUpdate(req.body, res)
)
then set ur webhook manually
https://api.telegram.org/bot{BOTTOKEN}/setWebhook?url={FIREBASE FUNCTION URL}'

Is there cloud functions that trigger if database changes and send notification to users subscriber to 'topics'

I am working in an android app project for my college minor project. Everything is working but now i want to add a notification feature, i.e whenever a admin posts a notice every user subscriber to that topic gets notification, i tried to follow different tutorials and documents but since i have no programming background in js/nodejs/php i couldn't understand the cloud functions.
Can anyone write the functions or lead me to the answer?
i want the function to be triggered when a new notice is added inside /Notice and send notification to all users subscribe to Notice..
i wrote the following code, after some study,
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotices =
functions.database.ref('/Notices/{nID}').onCreate((event) => {const data =
event.data;
if(!data.changed()){
console.log('Nothing changed');
return;
}else{
console.log(data.val());
}
const payLoad = {
notification:{
title: 'Message received',
body: 'You received a new message',
sound: "default"
}
};
const options = {
priority: "high",
timeToLive: 60*60*2
};
return admin.messaging().sendToTopic("bctb", payLoad, options);});
and got the error in console of firebase,what am i doing wrong here,
TypeError: Cannot read property 'changed' of undefined
at exports.sendNotices.functions.database.ref.onCreate
(/user_code/index.js:8:13)
at cloudFunctionNewSignature (/user_code/node_modules/firebase-
functions/lib/cloud-functions.js:105:23)
at cloudFunction (/user_code/node_modules/firebase-functions/lib/cloud-
functions.js:135:20)
at /var/tmp/worker/worker.js:770:24
at process._tickDomainCallback (internal/process/next_tick.js:135:7)
Since you are not familiar with the Firebase Cloud Functions, I recommend you first go through official docs here, because without going through the basics you won't understand how they work and then go through Firebase Cloud Messaging (FCM) docs here. Once you get to know how both the service work it'll be a lot easier for you to understand and write your own cloud function. For your ease here is how your function should be like.
You can do this by simply creating an onCreate trigger function. So it will look something like:
exports.SendNotification = functions.database.ref('/Notice/{nid}')
.onCreate((snapshot, context) => {
//Your notification code here
}
Here nid is the notice id that is just created. Firebase will automatically get this id. And for sending the notification you can use Firebase cloud messaging (FCM). In this cloud function you can create a notification payload.
//send notification
const payload = {
data:{
title: "New notice has been added!",
}
};
Now you can send this notification to the app using:
admin.messaging().sendToDevice(instID, payload);
Here, instID is the instance ID. Each app installed has a unique instance ID. For sending to multiple devices you'll have to wrap the code line above in an loop to send notifications to all of the subscribed users. For this you need instance IDs of all the subscribed users.
"I hear and I forget, I see and I remember, I do and I understand"
Best of luck.

Dialogflow fullfilment on firebase function if ask from telegram

I wrote function which work on firebase function and which take an answer on request if request come from the dialog console or the Google Assistant emulator. But if I ask from Telegram this function doesn't work.
Answer like Say that one more time? or if I filled the form Responses on web I have this response.
How connect firebase function with Telegram?
'use strict';
const {
dialogflow,
Permission,
Suggestions,
BasicCard,
} = require('actions-on-google');
const firebase = require('firebase');
const functions = require('firebase-functions');
const app = dialogflow({debug: true});
app.intent('simple word', (conv) => {
conv.ask(`it's ok`);
});
exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
The problems is that you're using the actions-on-google library, which is specifically designed to send results to the Assistant.
If you want to be able to send results to Telegram, you need to use the dialogflow-fulfillment library, which handles things slightly differently.

Can you trigger a Google Cloud Functions via firebase event without a server?

I will be implementing an elastic search index alongside my firebase application so that it can better support ad-hoc full text searches and geo searches. Thus, I need to sync firebase data to the elastic search index and all the examples require a server process that listens for firebase events.
e.g. https://github.com/firebase/flashlight
However, it would be great if I can just have a google cloud function triggered by an insert in a firebase node. I see that google cloud functions has various triggers: pub sub, storage and direct... can any of these bridge to a firebase node event without an intermediate server?
firebaser here
We just released Cloud Functions for Firebase. This allows you to run JavaScript functions on Google's servers in response to Firebase events (such as database changes, users signing in and much more).
I believe Cloud Functions for Firebase are what you are looking for.
Here are a few links:
Official Documentation
Intro video
Google Cloud Functions and Firebase (Google Cloud Next '17)
yes, you can trigger a Google Cloud Functions via firebase event without a server.
As per documents,Firebase allows for example you can send notifications using a cloud function when a user write into firebase database.
For that, I had to write a javascript as below
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.database.ref('/articles/{articleId}')
.onWrite(event => {
// Grab the current value of what was written to the Realtime Database.
var eventSnapshot = event.data;
var str1 = "Author is ";
var str = str1.concat(eventSnapshot.child("author").val());
console.log(str);
var topic = "android";
var payload = {
data: {
title: eventSnapshot.child("title").val(),
author: eventSnapshot.child("author").val()
}
};
// Send a message to devices subscribed to the provided topic.
return admin.messaging().sendToTopic(topic, payload)
.then(function (response) {
// See the MessagingTopicResponse reference documentation for the
// contents of response.
console.log("Successfully sent message:", response);
})
.catch(function (error) {
console.log("Error sending message:", error);
});
});

Resources