Issue connecting to token server with Firebase hosting - reactjs

I am trying to deploy the Twilio video app to Firebase hosting. Everything works great, except when I try to connect to video conference it tells me the Twilio tokens are invalid.
I found that I need to set up google cloud functions to resolve this. How do you go about converting a server.js file to a cloud function?
Here is my code server.js code:
const express = require('express');
const app = express();
const path = require('path');
const AccessToken = require('twilio').jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
require('dotenv').config();
const MAX_ALLOWED_SESSION_DURATION = 14400;
const twilioAccountSid = process.env.TWILIO_ACCOUNT_SID;
const twilioApiKeySID = process.env.TWILIO_API_KEY_SID;
const twilioApiKeySecret = process.env.TWILIO_API_KEY_SECRET;
app.use(express.static(path.join(__dirname, 'build')));
app.get('/token', (req, res) => {
const { identity, roomName } = req.query;
const token = new AccessToken(twilioAccountSid, twilioApiKeySID, twilioApiKeySecret, {
ttl: MAX_ALLOWED_SESSION_DURATION,
});
token.identity = identity;
const videoGrant = new VideoGrant({ room: roomName });
token.addGrant(videoGrant);
res.send(token.toJwt());
console.log(`issued token for ${identity} in room ${roomName}`);
});
app.get('*', (_, res) => res.sendFile(path.join(__dirname, 'build/index.html')));
app.listen(8081, () => console.log('token server running on 8081'));
I'm thinking I can move that to the cloud functions index.js file and add the following to still connect to my .env file variables if I put the express function in here:
const functions = require('firebase-functions');
const config = functions.config();
// Porting envs from firebase config
for (const key in config.envs){
process.env[key.toUpperCase()] = config.envs[key];
}

To convert this to a Firebase cloud function, you need to remove server listeners and you have to setup a local Firebase environment to deploy and develop
Steps to convert cloud function
# Install firebase-tools
npm install -g firebase-tools
# Login and initialize project
firebase login
firebase init functions
# For local dev
firebase serve
# Deploy the function to cloud
firebase deploy
Your current code will look something like this after converting to cloud function
You can also make each routes into separate modules
const functions = require('firebase-functions');
const express = require('express');
const app = express();
const path = require('path');
const AccessToken = require('twilio').jwt.AccessToken;
const VideoGrant = AccessToken.VideoGrant;
require('dotenv').config();
const router = express.Router();
const MAX_ALLOWED_SESSION_DURATION = 14400;
const twilioAccountSid = process.env.TWILIO_ACCOUNT_SID;
const twilioApiKeySID = process.env.TWILIO_API_KEY_SID;
const twilioApiKeySecret = process.env.TWILIO_API_KEY_SECRET;
app.use(express.static(path.join(__dirname, 'build')));
router.get('/token', (req, res) => {
const { identity, roomName } = req.query;
const token = new AccessToken(twilioAccountSid, twilioApiKeySID, twilioApiKeySecret, {
ttl: MAX_ALLOWED_SESSION_DURATION,
});
token.identity = identity;
const videoGrant = new VideoGrant({ room: roomName });
token.addGrant(videoGrant);
res.send(token.toJwt());
console.log(`issued token for ${identity} in room ${roomName}`);
});
router.get('*', (_, res) => res.sendFile(path.join(__dirname, 'build/index.html')));
// Your cloud function will be like : https://<region>-<appname>.cloudfunctions.net/twilioApp
exports.twilioApp = functions.https.onRequest(router);
Please read the official documentation here

Related

Google Spreadsheet Api not working on mobile devices

I'm using Google Spreadsheets as a lightweight database for my React App. The app is a wedding website and the idea is for users to be able to RSVP and the response gets saved in a Google Spreadsheet. See GitHub for a visual representation of what I mean: https://github.com/michelleroos/mimirgettingmarried
It's working as intended on desktop, meaning RSVP responses get saved to the sheet, but not on mobile and I can't figure out why.
Would love your input! If I could even just understand where to start looking that would be great but there is not a lot of information out there on Google Spreadsheet Api.
const express = require("express");
const app = express();
const { google } = require('googleapis');
const PORT = process.env.PORT || 3001; // use live port or the declared one
var cors = require('cors');
app.use(cors())
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
const auth = new google.auth.GoogleAuth({
keyFile: "./config/credentials.json",
scopes: 'https://www.googleapis.com/auth/spreadsheets',
});
const spreadsheetId = "1-R0vjBCOD5hcipk9AQbVUwQAH_0dFvQB2qs5gxsxWg0";
const range = "rsvp";
// api endpoint returns a CB. We decide what to do w res thru CB
app.get("/api/rsvp", async (req, res) => {
// create client instance for auth
const client = await auth.getClient();
// create Google sheets API instance
const googleSheets = google.sheets({ version: "v4", auth: client })
// read rows
const getRows = await googleSheets.spreadsheets.values.get({
auth,
spreadsheetId,
range,
});
// express/app sends to the client (the body)
res.send(getRows.data.values);
});
app.post("/api/rsvp", async (req, res) => {
// create client instance for auth
const client = await auth.getClient();
// create Google sheets API instance
const googleSheets = google.sheets({ version: "v4", auth: client })
const writeRows = await googleSheets.spreadsheets.values.append({
auth,
spreadsheetId,
range,
valueInputOption: "USER_ENTERED", // parses info
resource: {
values: [
// Object.keys(req.body), // header
Object.values(req.body) // values
]
}
})
res.send(writeRows);
});
app.listen(PORT, () => {
console.log(`Server listening on ${PORT}`);
});

register user using json and local storage

I'm trying to create a webapp where a user can log in and register.
I have to store the user list locally, meaning no db is allowed, and I have a json file called "usersDB" instead.
I thought about creating the register using append or push but it doesn't seem to work, any idea how to add a new user?
my code:
let userFile = require ("./users.json");
const express = require("express");
const {v4: uuidv4} = require('uuid');
const port = process.env.PORT || 3005;
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(express.json());
app.get("/users",((req, res) => {
res.status(200).send(userFile);
}))
app.get("/products",((req, res) => {
res.status(200).send(productFile);
}))
app.post(`/register`, async (req, res, next) => {
if(req.body.username.valueOf()===undefined||req.body.password.valueOf()===undefined ){
res.err("undefined");
}
let id = genarateUuid();
// createUser
//add to db
let user = {id:id,username:req.body.username,password:req.body.password,cart:[],purchases:[],login:[],sessions:[],isAdmin: false};
userFile.append(user); //doesn't seem to work
res.status(200).json(user);
}
)
Looks like you're using node and express. You'll need to use fs to read/write to files (and I like to use path in combination with fs to build the file paths).
To write to a file (Assuming users.json contains an array of user objects):
const fs = require('fs');
app.post('/register', async (req, res, next) => {
// build user variable...
// read current file contents
const filePath = path.join(process.cwd(), 'users.json');
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
// append the new user
data.push(user);
// write the file back to users.json
fs.writeFileSync(filePath, JSON.stringify(data));
res.status(200).json(user);
});
To read from that file:
app.get('/users', (req, res) => {
// read current file contents
const filePath = path.join(process.cwd(), 'users.json');
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
res.status(200).json(data);
});
You could also refactor that code a bit more to avoid code repeat.
For instance, make a function called getUsers:
const getUsers = (filePath) => {
const fileData = fs.readFileSync(filePath);
const data = JSON.parse(fileData);
return data;
}
Hope this helps you out!

React app deploying on heroku, not loading DB from mlab

When I run heroku local, app working as expecting.
On production, it's not loading anything from Mlab (remote mongoDb)
Here is it
https://react-bulletin.herokuapp.com/
Just showing static react file.
here is my server file
require('dotenv').config();
// Express Stuff
const express = require('express');
const app = express();
const cors = require('cors')
const path = require('path')
// Mongo Wrapper
const mongoose = require('mongoose');
// Supporting Libraries
const bodyParser = require('body-parser');
// Globals
const dbUrl = process.env.MONGODB_URI
const port = process.env.PORT
mongoose.connect(dbUrl, {
useNewUrlParser: true,
useFindAndModify: false
});
app.use(cors())
app.use(bodyParser.json());
app.use('/', require('./Routes'));
if (process.env.NODE_ENV === 'production') {
// Serve any static files
app.use(express.static(path.join(__dirname, 'client/build')));
// Handle React routing, return all requests to React app
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Running at http://localhost:${PORT}`);
I have no idea why is that.
Please any help.
PS
MONGODB_URI is added to heroku varibles.

Express.js - can find my route

I'm using react.js and express.js and getting 404 error on my fetch request.
I'm simply trying to have my routes return testing express.js...
[app.js]
'use strict';
const NODE_ENV = process.env.NODE_ENV;
const PORT = process.env.PORT;
const next = require('next');
const express = require('express');
const api = require('./api');
const client = next({ dev: NODE_ENV === 'development' });
const clientHandler = client.getRequestHandler();
const app = express();
client.prepare().then(() => {
app.use('/api', api);
app.get('*', (req, res) => clientHandler(req, res));
});
const listener = app.listen(PORT, err => {
if (err) throw err;
console.log('listening on port: %d', listener.address().port); //eslint-disable-line
});
[/api/index.js]
'use strict';
const express = require('express');
const app = express();
app.get('/api/test', function (req, res) {
res.send('testing express.js...');
});
module.exports = app;
[Body.js]
import React from 'react';
export default class Body extends React.Component {
constructor(props) {
super(props);
this.fetchContacts = this.fetchContacts.bind(this);
}
componentDidMount() {
this.fetchContacts();
}
async fetchContacts() {
const res = await fetch('/api/test');
const contacts = await res.json();
log(contacts);
this.setState({ contacts });
}
render() {
return <div>hello world!</div>;
}
}
Question: Why am I getting a 404 error?
To make your /api/test route work properly, you need to change this:
app.get('/api/test', function (req, res) {
res.send('testing express.js...');
});
to this:
app.get('/test', function (req, res) {
res.send('testing express.js...');
});
Your router is already looking at /api so when you then put a route on the router for /api/test, you were actually making a route for /api/api/test. To fix it, make the above change.
Also, your index.js file should not be using an app object. It should be using an express.Router() object, though an app object is also a router so it might kind of work, but it's not the way it should be done.
That is not the way to load a react JS file on nodejs, follow this basic (React + NodeJS) guide:
https://blog.yld.io/2015/06/10/getting-started-with-react-and-node-js/#.Wd7zSBiWbyg
Or use "create-react-app" :
https://medium.com/#patriciolpezjuri/using-create-react-app-with-react-router-express-js-8fa658bf892d

Google Cloud speech with React Native

I am trying to use Google Cloud Speech API so I can pass audio file and receive the translated text but I am stuck to the integration. I already have api key and everything needed but can't find how to use it from react native. In the documentation there is only explanation for node.js (from javascript part). Also there are several libraries out dated or supporting only the one OS. Someone succeeded in that?
The node.js example from the documentation:
// Imports the Google Cloud client library
const Speech = require('#google-cloud/speech');
// Your Google Cloud Platform project ID
const projectId = 'YOUR_PROJECT_ID';
// Instantiates a client
const speechClient = Speech({
projectId: projectId
});
// The name of the audio file to transcribe
const fileName = './resources/audio.raw';
// The audio file's encoding and sample rate
const options = {
encoding: 'LINEAR16',
sampleRate: 16000
};
// Detects speech in the audio file
speechClient.recognize(fileName, options)
.then((results) => {
const transcription = results[0];
console.log(`Transcription: ${transcription}`);
});
You could deploy the code using google app engine and make a post req from react-native.
Also need to configure and use google cloud storage to store the audio file for conversion.
Here is my server code.
const format = require('util').format;
const fs = require('fs');
const express = require('express');
const multer = require('multer');
const requestHttp = require('request');
const {Storage} = require('#google-cloud/storage');
// Instantiate a storage client
const storage = new Storage();
// const upload = multer();
const app = express();
// Imports the Google Cloud client library
const speech = require('#google-cloud/speech');
// Creates a client
const client = new speech.SpeechClient();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
const encoding = 'LINEAR16';
const sampleRateHertz = 16000;
const languageCode = 'en-US';
const upload = multer({
storage: multer.memoryStorage(),
limits: {
fileSize: 5 * 1024 * 1024, // no larger than 5mb, you can change as needed.
},
});
const bucket = storage.bucket(process.env.GCLOUD_STORAGE_BUCKET);
app.post('/upload', upload.single('file') , async (req, res) => {
const file = await req.file
if (!file) {
const error = new Error('Please upload a file')
error.httpStatusCode = 400
return next(error)
}
// Create a new blob in the bucket and upload the file data.
const blob = bucket.file(req.file.originalname);
const blobStream = blob.createWriteStream({
resumable: false,
});
blobStream.on('error', err => {
next(err);
});
blobStream.on('finish', async () => {
// The public URL can be used to directly access the file via HTTP.
const publicUrl = await format(
`https://storage.googleapis.com/${bucket.name}/${blob.name}`
);
const request = {
config: {
encoding: encoding,
sampleRateHertz: sampleRateHertz,
languageCode: languageCode,
},
audio: {
uri: 'gs://YOUR-Bucket-Name/File-name.ext'
}
};
// Stream the audio to the Google Cloud Speech API
const [response] = await client.recognize(request);
const transcription = response.results
.map(result => result.alternatives[0].transcript)
.join('\n');
console.log(`Transcription: `, transcription);
res.status(200)
.send({
success: 'true',
message: 'Text retrieved successfully',
text: transcription
})
.end();
});
blobStream.end(req.file.buffer);
});
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}`);
console.log('Press Ctrl+C to quit.');
});
deploy this server to Heroku then from your react native app send the post or get request to this server and get the result on your app.
To send post or get request use Axios library https://github.com/axios/axios

Resources