I have a react APP that uses the AWS Amplify PubSub library.
I have an IoT device that connect to AWS IoT and publishes message on topic/pub (topic).The message is only sent once (from the device) and when I see it in the AWS MQTT client console I can only see only 1 message (as expected) but in the react application I'm receiving multiple messages in the console.
App.js
...
import {Amplify} from 'aws-amplify';
import awsconfig from './aws-exports';
// import { withAuthenticator } from 'aws-amplify-react'; // or 'aws-amplify-react-native';
import { withAuthenticator, Button, Heading } from '#aws-amplify/ui-react';
import '#aws-amplify/ui-react/styles.css';
import { Auth } from 'aws-amplify';
Amplify.configure(awsconfig);
// Auth.currentCredentials().then(creds => console.log(creds));
function App() {
return (
...
export default withAuthenticator(App,true);
Device Page.js
import {Amplify} from 'aws-amplify';
import awsconfig from './../aws-exports';
import { PubSub } from 'aws-amplify';
import { AWSIoTProvider } from '#aws-amplify/pubsub/lib/Providers';
Amplify.configure(awsconfig);
Amplify.addPluggable(new AWSIoTProvider({
aws_pubsub_region: 'xx-xxxxxxx-x',
aws_pubsub_endpoint: 'wss://<My endpoint from AWS IoT>/mqtt',
}));
function GaugesComponent ({id}) {
PubSub.subscribe('test/pub').subscribe({
next: data => {
console.log(data.value);
},
error: error => console.error(error),
complete: () => console.log('Done'),
},);
return (
...
export default GaugesComponent;
When my device publishes or I use the AWS MQTT client to publish a message the message is logged multiple times in the console.
Images:
AWS MQTT client console
console log messages of react app
Instead of adding the below code in the device.js where I'm subscribing to the MQTT topic I only added it once in my app.js after Amplify.configure(); like this
App.js
Amplify.configure(awsconfig);
Amplify.addPluggable(new AWSIoTProvider({
aws_pubsub_region: 'xx-xxxxxxx-x',
aws_pubsub_endpoint: 'wss://<My endpoint from AWS IoT>/mqtt',
}));
Then I subscribe to the topic using useEffect() like this in my device.js
Device.js
sub_topic = PubSub.subscribe(id+'/live').subscribe({
next: data => {/*do stuff with received data*/},
error: error => console.error(error),
complete: () => console.log('Done'),
},);
return ()=>{
sub_topic.unsubscribe();
console.log("Unsubscribed to topic");
}
},[]);
Related
Im building a web chat app with next.js and im trying to implement push notifications with firebase but im getting stuck on this error:
error - unhandledRejection: FirebaseError: Messaging: This browser doesn't support the API's required to use the Firebase SDK. (messaging/unsupported-browser)
error - Error: Service messaging is not available.
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import { getStorage } from "firebase/storage";
import { getMessaging } from "firebase/messaging";
const firebaseConfig = {
...
};
const app = !firebase.apps.length
? firebase.initializeApp(firebaseConfig)
: firebase.app();
const messaging=getMessaging(app)
const db =app.firestore();
const auth=app.auth();
const provider=new firebase.auth.GoogleAuthProvider();
export const storage = getStorage(app);
export{db,auth,provider};
What can i do to solve this problem?
I created a Google Cloud Platform account, and made a simple hello_world type Python "Cloud Function" that just spits out some simple text. I made this function "HTTP" accessible and only able to be called/authenticated by a "Service Account" that I made for the purpose of calling this very function. I generated a key for this "Service Account" and downloaded the json file for the key.
The problem is that I can't find any documentation on how to call this function with my service account in a next.js app. I tried this:
import React from 'react';
import { Button } from 'react-bootstrap';
import { GoogleAuth } from 'google-auth-library';
const projectId = 'gtwitone';
const keyFilename = '/Users/<myusername>/path/to/cloudfunction/credentials.json';
class Middle extends React.Component {
handleClick() {
console.log('this is:', this);
}
// This syntax ensures `this` is bound within handleClick. // Warning: this is *experimental* syntax. handleClick = () => { console.log('this is:', this); }
/* async listFunctions() {
const [functions] = await client.listFunctions();
console.info(functions);
} */
async runGoogleCloudFunctionTest() {
// Define your URL, here with Cloud Run but the security is exactly the same with Cloud Functions (same underlying infrastructure)
const url = "https://us-central1-<projectname>.cloudfunctions.net/<functionname>"
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({keyFilename: keyFilename})
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url);
const res = await client.request({url});
console.log(res.data);
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant='primary' onClick={this.runGoogleCloudFunctionTest}>
Click me
</Button>
</div>
);
}
}
export default Middle;
But I got this error in my terminal:
<myusername>#<mycomputername> <thisnextjsappdirectory> % yarn dev
yarn run v1.22.17
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
wait - compiling...
event - compiled client and server successfully in 267 ms (124 modules)
wait - compiling / (client and server)...
wait - compiling...
error - ./node_modules/google-auth-library/build/src/auth/googleauth.js:17:0
Module not found: Can't resolve 'child_process'
Import trace for requested module:
./node_modules/google-auth-library/build/src/index.js
./components/Middle.tsx
./pages/index.tsx
https://nextjs.org/docs/messages/module-not-found
Native Node.js APIs are not supported in the Edge Runtime. Found `child_process` imported.
Could not find files for / in .next/build-manifest.json
Could not find files for / in .next/build-manifest.json
^C
<myusername>#<mycomputername> <thisnextjsappdirectory> %
I know that this is problem with server side rendering in my Next.js app and people recommend using a client side package like this https://github.com/google/google-api-javascript-client. But google-api-javascript-client doesn't have any documentation on authenticating with a .json credentials file instead of an API KEY which I do not have.
In short how do I get my app to work and run the Google Cloud function with a .json credentials file for am authenticated service account?
I fixed it by simply moving the GoogleAuth api call to the pages/api route.
pages/api/google.ts
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from "next"
import { GoogleAuth } from "google-auth-library"
export default async function handler(req: NextApiRequest, res: NextApiResponse<any>) {
const url = process.env.FUNCTION_URL as string
//Example with the key file, not recommended on GCP environment.
const auth = new GoogleAuth({ keyFilename: process.env.KEYSTORE_PATH })
//Create your client with an Identity token.
const client = await auth.getIdTokenClient(url)
const result = await client.request({ url })
console.log(result.data)
res.json({ data: result.data })
}
components/Middle.tsx
import React from "react"
import { Button } from "react-bootstrap"
class Middle extends React.Component {
handleClick() {
console.log("this is:", this)
}
// this talks with /pages/api/google
async imCallingAnAPI() {
const result = await fetch("/api/google")
console.log({ result })
}
render() {
return (
<div className="col-md-12 text-center">
<Button variant="primary" onClick={this.imCallingAnAPI}>
Click me
</Button>
</div>
)
}
}
export default Middle
pages/index.tsx
import type { NextPage } from 'next'
import Header from '../components/Header';
import Footer from '../components/Footer';
import Middle from '../components/Middle';
const Home: NextPage = () => {
return (
<><main className='d-flex flex-column min-vh-100'>
<Header />
<br></br>
<br></br>
<Middle />
</main>
<footer>
<Footer />
</footer>
</>
)
}
export default Home
I think that next.js has trouble loading GoogleAuth in a component. I'm not 100% sure why, but I think it has to do with next.js not knowing exactly how to handle GoogleAuth with server-side rendering.
I'm using firebase stripe extension "run subscriptions with stripe". In this extension integration i'm not able to redirect the checkout page (redirectToCheckout function did not work)..Any ideas how can i do that???
Here is my stripe webhooks events:
customer.subscription.updated
customer.subscription.deleted
customer.subscription.created
checkout.session.completed
price.updated
price.deleted
price.created
product.updated
product.deleted
product.created
Here is my first screen code in which user is creating...!
import firebase from 'firebase';
// import getStripe from './stripe';
import { loadStripe } from '#stripe/stripe-js/pure';
import '#stripe/stripe-js';
import redirectToCheckout from '#stripe/stripe-js';
const firestore = firebase.firestore();
firebase.auth().onAuthStateChanged((user) => {
if (user) {
console.log(user.uid)
// User logged in already or has just logged in.
} else {
// User not logged in or has just logged out.
}
});
export async function createCheckoutSession(){
let uid = "static uid";
const checkoutSessionRef = await firestore.collection('stripe').doc(uid).collection('checkout_sessions').add(
{price : 'price id',
success_url : 'https://localhost:3000/success',
cancel_url: 'https://localhost:3000/fail',
});
checkoutSessionRef.onSnapshot(async (snap) => {
const {error , sessionId} = snap.data();
if (error) {
// Show an error to your customer and
// inspect your Cloud Function logs in the Firebase console.
alert(`An error occured: ${error.message}`);
}
if (sessionId) {
const stripe = await loadStripe('pk_test_1234');
stripe.redirectToCheckout({ sessionId });
}
});
}
I am using the same code and it's working fine. The only difference I see here which might be the reason for your problem is that you are importing loadStripe from #stripe/stripe-js/pure which might need to be from "#stripe/stripe-js" and I don't think you need any other stripe import, for example, your imports should be like
import firebase from 'firebase';
import { loadStripe } from '#stripe/stripe-js';
I have these imports and they are working fine
I am working on a React.js + firebase app, using Twitter login (see Login.js below).
This code works most of the time (>90%), but it often fails with the following error.
Screen: Malformed response cannot be parsed from twitter.com for OAUTH1_REQUEST_TOKEN
Console: [Error] Failed to load resource: the server responded with a status of 400 () (verifyAssertion, line 0)
Everything works fine with Email login. This problem happens only if I use Twitter login.
I am wondering if I am doing something wrong or missing something. I'd appreciate any suggestions.
import React from 'react';
import * as firebase from "firebase/app";
import "firebase/auth";
import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth';
import { Redirect } from 'react-router-dom';
const uiConfig = {
signInFlow: 'popup',
signInOptions: [
firebase.auth.TwitterAuthProvider.PROVIDER_ID
],
callbacks: {
// Avoid redirects after sign-in.
signInSuccessWithAuthResult: (result) => {
return false;
}
}
};
class Login extends React.Component {
render() {
if (!this.props.user) {
return <div>
<StyledFirebaseAuth uiConfig={uiConfig} firebaseAuth={firebase.auth()}/>
</div>
}
return <Redirect to="/Main" />
}
}
export default Login;
I am trying to send a push notification to my ios device from the Firebase console by token ID. I am using react-native-firebase to allow the app to perform actions based on the notification events. I followed the instructions to integrate the SDK and have set up the APNS certs etc:
http://invertase.io/react-native-firebase/#/installation-ios
My firebase.js config file looks like this:
import RNFirebase from 'react-native-firebase';
const configurationOptions = {
debug: true
};
const firebase = RNFirebase.initializeApp(configurationOptions);
export default firebase;
My main React component looks like this:
import React, { Component } from 'react'
import {
Text,
View,
Alert,
Platform
} from 'react-native'
import firebase from './firebase'
export default class extends Component {
constructor(props) {
super(props)
this.state = {
token: ''
}
}
componentDidMount() {
firebase.messaging().getToken()
.then((token) => {
this.setState({ token })
console.log('token: ', token)
})
firebase.messaging().getInitialNotification()
.then((notification) => {
console.log('Notification which opened the app: ', notification)
})
firebase.messaging().onMessage((message) => {
console.log('messaging', message)
})
firebase.messaging().onTokenRefresh((token) => {
console.log('Refreshed FCM token: ', token)
})
}
render() {
return (
<View style={{ marginTop: 22 }}>
<Text>{this.state.token}</Text>
</View>
)
}
}
I successfully get the token when the component mounts and then use that in the Firebase console to send a notification, but the notification is not received. I am using a real device, not and iPhone. I am using a development provisioning profile with Push notifications enabled and the remove notifications back ground entitlement enabled successfully, along with the appropriate development APNs certificate, which has been uploaded to the firebase console.
Why am I not receiving the notification on the device?
Okay, it looks like it was just ignoring the remote notifications because I had not requested permissions from the user. Just needed to do that via the SDK:
componentDidMount() {
firebase.messaging().requestPermissions()
firebase.messageing().getToken().then...