Trying to subscribe to topic on Firebase Cloud Messaging gives Error - javascript

When i try to subscribe to a topic i get the following error:
.subscribeToTopic is not a function
const messaging = firebase.messaging();
messaging
.requestPermission()
.then(() => {
return messaging.getToken();
})
.then(token => {
messaging
.subscribeToTopic(token, 'allUsers')
.then(response=> {
console.log(JSON.stringify(response));
})
.catch(function(error) {
console.log('Error subscribing to topic:', error);
});
})
.catch(err => {
console.log('Unable to get permission to notify.', err);
});
If I remove that line of .subscribeToTopic and add a POST call via http it works using the following url:
https://iid.googleapis.com/iid/v1/TOKEN/rel/topics/TOPIC_NAME
I took a look to this question and the docs
Cloud Messaging in Cloud Functions: admin.messagin(...).send is not a function
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging

ah i solved it by handling on backend side ( nodeJS ) where the documentation is easy to handle topic.
so in this case we have alr generate token on frontend side then in backend (nodeJS) we tried to subscribe to topic by the token.
so in frontend end when we stream or firebase.messaging().onMessage(payload => { would like to trigger and show the message by topic.
FYI : https://github.com/firebase/firebase-js-sdk/issues/5289#issuecomment-899542765
so from the link we know that
Notification.vue
// these from frontend side ( for example vueJS )
import firebase from 'firebase/app'
import 'firebase/messaging'
// firebase only for get token, onMessaging, request permission check, there is no function to subscribe topic by the token, so we handle on backend side my alternative
then in server.js
// these from backend side ( for examle nodeJS )
const { admin } = require('./firebase-config');
// admin.messaging().sendToTopic()
// admin.messaging().subscribeToTopic()
// admin.messaging().sendToDevice()
if you are looking for the firebase-config.js here is
/*
* Initialize firebase
*/
var admin = require("firebase-admin");
var serviceAccount = require("./firebase.json"); // you can get the .json file on firebase service account .
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://project-xxxxxxx.firebaseio.com"
});
module.exports.admin = admin
my implementation :
app.get('/firebase/notification', (req, res)=>{
const registrationToken = req.body.registrationToken;
admin.messaging().subscribeToTopic(registrationToken, 'myTopic')
.then(response => {
console.log('Successfully subscribed to topic:', response)
const options = notification_options;
const message_notification = {
notification: {
title: 'Yogi Arif Widodo',
body: '2 10 pm',
url: 'https://localhost:8080',
other: 'other data',
}
};
admin.messaging().sendToTopic('myTopic', message_notification, options).then( response => {
so when i tested on firebase console send by topic myTopic my Notification.vue trigger these code
firebase.messaging().onMessage(payload => {
.....console.log
}

You need to use the method send not sendToTopic:
// The topic name can be optionally prefixed with "/topics/".
var topic = 'highScores';
var message = {
data: {
score: '850',
time: '2:45'
},
topic: topic
};
// Send a message to devices subscribed to the provided topic.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
send() was released and replaced sendtotopic/sendtodevice in version FCM v1
https://firebase.googleblog.com/2018/02/firebase-cloud-messaging-v1-now.html
https://firebase.google.com/docs/cloud-messaging/js/topic-messaging

Related

after deploy, fcm alert function is not working... java.lang.IllegalArgumentException: Exactly one of token, topic or condition must be specified

I made alert service using FCM, it works fine in my local server. but after I deployed my server in ec2, trying alert function on ec2 app gives me this error :
[ient-SecureIO-1] o.a.t.websocket.pojo.PojoEndpointBase : No error handling configured for [springboot.utils.WebsocketClientEndpoint] and the following error occurred
java.lang.IllegalArgumentException: Exactly one of token, topic or condition must be specified
Reading the error message, i guess that there's no token in my server.
In notification.js, I'm trying to get token and request POST to '/register'
const firebaseModule = (function () {
async function init() {
// Your web app's Firebase configuration
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/firebase-messaging-sw.js')
.then(registration => {
var firebaseConfig = {
configuration Information
};
// Initialize Firebase
console.log("firebase Initialization");
firebase.initializeApp(firebaseConfig);
// Show Notification Dialog
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function() {
console.log("Permission granted to get token");
return messaging.getToken();
})
.then(async function(token) {
console.log("Token: ", token);
await fetch('/register', { method: 'post', body: token })
messaging.onMessage(payload => {
const title = payload.notification.title
const options = {
body : payload.notification.body
}
navigator.serviceWorker.ready.then(registration => {
registration.showNotification(title, options);
})
})
})
.catch(function(err) {
console.log("Error Occured : " +err );
})
})
})
}
}
And by debugging it by console.log(), I found out that code is stopped before "if ('serviceWorker' in navigator) {"
So I need to make it proceed. But to be honest, it's been a while since i made this function, and I don't know almost anything about Javascript. I don't even know what navigator means(I googled it, but couldn't find clear answer) I'm having trouble figuring out what is wrong and how can I fix it. Can someone help me??

Twilio conversations push notifications not working - Empty Credentials error

I need to enable push notifications in my project. I have already integrated twilio conversations.
I followed this documentation and seems to be ok, but there is a problem with the setPushRegistrationId method.
I have this code:
import { getMessaging, getToken, onMessage } from "firebase/messaging";
import initFirebase from "../firebase/initFirebase";
export const handleNotifications = async (conversationClientInstance) => {
const app = initFirebase();
const messaging = getMessaging(app);
getToken(messaging, {
vapidKey:
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
})
.then((currentToken) => {
if (currentToken) {
console.log("currentToken", currentToken);
//Here is the problem <----------
conversationClientInstance
.setPushRegistrationId("fcm", currentToken)
.then((el) => console.log("el", el));
onMessage((payload) => {
conversationClientInstance.handlePushNotification(payload);
});
} else {
// Show permission request UI
console.log(
"No registration token available. Request permission to generate one."
);
// ...
}
})
.catch((err) => {
console.log("An error occurred while retrieving token. ", err);
// ...
});
};
I am getting this error on the twilio dashboard:
I also replicated this situation in this github repo. It is deployed, so you can try it live.
In console I can see the FCM token, but setPushRegistrationId returns undefined (the console.log('el', el))
I think I forgot something, but I can't figure out what. What do you thik?

Sending Custom Tokens Back To Client From Firebase Admin

I am working with the Firebase Admin SDK for Nodejs so that I can mint custom tokens for authentication in iOS devices. In the Nodejs docs it states that you send the token back to the client after it is created.
let uid = 'some-uid';
admin.auth().createCustomToken(uid)
.then(function(customToken) {
// Send token back to client
})
.catch(function(error) {
console.log('Error creating custom token:', error);
});
My question is the most efficient way to do this. I've been thinking about creating Could Function to send it back in a response body but I feel like I may be over thinking it. Is this the recommended method or is there a simpler way I am missing?
Here is the working code from my application (cloud function) that is as simple as copy paste for your reference.
exports.getCustomToken = functions.https.onRequest(async (req, res) => {
return cors(req, res, async () => {
try {
const token = await createCustomToken(req.body.uid);
return res.json(token);
} catch (error) {
res.status(500).json({ message: 'Something went wrong' });
}
});
});
async function createCustomToken(userUid, role = '') {
let createdCustomToken = '';
console.log('Ceating a custom token for user uid', userUid);
await firebaseAdmin.auth().createCustomToken(userUid)
.then(function (customToken) {
// Send token back to client
console.log('customToken is ', customToken)
createdCustomToken = customToken;
})
.catch(function (error) {
console.log('Error creating custom token:', error);
});
return createdCustomToken;
}
I wouldn't worry too much about efficiency at this point. The token is small and is quick to generate. The first thing to do is just make it work. Use Cloud Functions if you prefer, but the Admin SDK will work on any modern nodejs backend.

How do I listen for new uploads from a specific channel in the YouTube API?

I am making a Discord bot, and I want it to be able to use the YouTube API to fetch new uploads from a specific channel.
I have searched elsewhere, but they all say how to upload videos, not how to track uploads.
Is this possible, and how can I do it?
Edit: Tried PubSubHubbub but it was very confusing and I couldn't get it to work
Here an example built on top of Node.js (v12) and Fastify and published with ngrok:
I wrote some comments explaining what it is happening:
const fastify = require('fastify')({ logger: true })
const xmlParser = require('fast-xml-parser')
const { URLSearchParams } = require('url')
const fetch = require('node-fetch')
// add an xml parser
fastify.addContentTypeParser('application/atom+xml', { parseAs: 'string' }, function (req, xmlString, done) {
try {
const body = xmlParser.parse(xmlString, {
attributeNamePrefix: '',
ignoreAttributes: false
})
done(null, body)
} catch (error) {
done(error)
}
})
// this endpoint needs for authentication
fastify.get('/', (request, reply) => {
reply.send(request.query['hub.challenge'])
})
// this endpoint will get the updates
fastify.post('/', (request, reply) => {
console.log(JSON.stringify(request.body, null, 2))
reply.code(204)
reply.send('ok')
})
fastify.listen(8080)
.then(() => {
// after the server has started, subscribe to the hub
// Parameter list: https://pubsubhubbub.github.io/PubSubHubbub/pubsubhubbub-core-0.4.html#rfc.section.5.1
const params = new URLSearchParams()
params.append('hub.callback', 'https://1f3dd0c63e78.ngrok.io') // you must have a public endpoint. get it with "ngrok http 8080"
params.append('hub.mode', 'subscribe')
params.append('hub.topic', 'https://www.youtube.com/xml/feeds/videos.xml?channel_id=UCfWbGF64qBSVM2Wq9fwrfrg')
params.append('hub.lease_seconds', '')
params.append('hub.secret', '')
params.append('hub.verify', 'sync')
params.append('hub.verify_token', '')
return fetch('https://pubsubhubbub.appspot.com/subscribe', {
headers: { 'content-type': 'application/x-www-form-urlencoded' },
body: params,
method: 'POST'
})
})
.then((res) => {
console.log(`The status must be 204. Received ${res.status}`)
// shows the error if something went wrong
if (res.status !== 204) {
return res.text().then(txt => console.log(txt))
}
})
I used my channel id to do some testing, consider that the notification is not in real-time, the POSTs are triggered after several minutes usually.

Firebase Cloud Function never failing on 404 API call

I have a function running on the creation of a document.
When I send this information to an external API Firebase returns on 'ok' message before the API call is complete.
const functions = require('firebase-functions');
const request = require('request');
const admin = require('firebase-admin');
const rp = require('request-promise');
const port = '****';
const ip = '***.***.***.***';
admin.initializeApp(functions.config().firebase);
exports.sendUser = functions.firestore
.document('user/{userId}')
.onCreate((snap, context) => {
const data = snap.data();
const options = {
method: 'POST',
uri: 'http://' + ip + ':' + port + '/user',
body: data,
json: true,
};
rp(options)
.then(function (parsedBody) {
console.log('TEN ', parsedBody);
return parsedBody;
})
.catch(function (err) {
console.log('ERR ', err);
return err;
});
});
As you can see from my function it is not doing anything special apart from sending the data to an external source.
The API look like the following:-
app.post('/user', function (req, res) {
fs.exists(path, function(exists) {
if (exists === true) {
console.log('Currently Printing Different User Info');
fs.unlinkSync(path);
res.status(404).json({errorCode: 404, errorMessage: 'Currently Printing Different User.'});
return;
} else {
fs.writeFile(path, '', () => { console.log('File Created'); });
fs.unlinkSync(path);
res.status(200).json({statusCode: 200, statusMessage: 'Here we go'});
return;
}
});
})
How can I get Firebase to recognise the returned 404 as a failed call, and also wait until the call is complete before returning ok or failed.
The API is behaving correctly with Postman but not when data is posted via Firebase.
Has anyone encountered this before, or can anybody see what I am doing wrong?
The data is being parse over to the serve but only once Firebase has returned with 'ok' even if I purposely trigger a fail.
I need this in place to be able to use the Firebase Cloud Function retry function.
Images can be seen # https://imgur.com/a/1qYxrci
The Cloud Function returns the result before the call is complete because you don't return the Promise returned by the request-promise call.
Changing your code as follows should do the trick (at least for this problem):
exports.sendUser = functions.firestore
.document('user/{userId}')
.onCreate((snap, context) => {
const data = snap.data();
const options = {
method: 'POST',
uri: 'http://' + ip + ':' + port + '/user',
body: data,
json: true,
};
return rp(options) // <-- See the change here
.then(function (parsedBody) {
console.log('TEN ', parsedBody);
return parsedBody;
})
.catch(function (err) {
console.log('ERR ', err);
return err;
});
});
I would suggest you watch the official Video Series (https://firebase.google.com/docs/functions/video-series/) which explain very well this point about returning Promises for background functions (in particular the ones titled "Learn JavaScript Promises").

Categories

Resources