Amazon Alexa Skill Lambda code won't execute - javascript

I am trying to write the Lambda function for an Amazon Alexa skill in NodeJS. Alexa is that cylindrical speaker that responds to your voice, and a "skill" is basically a voice app for it. This function takes the JSON input from the Alexa device and creates a response, then sends the new JSON back to the device for output.
This code is supposed to pull the Bitcoin to USD exchange rate from the BTC-e JSON, extract the 'avg' value, and output it to the Alexa device.
I haven't done any coding in a long time, so please forgive any stupid errors. I took the example code and tried to modify it for my purposes, but I get this error when executing in AWS:
{
"errorMessage": "Unexpected identifier",
"errorType": "SyntaxError",
"stackTrace": [
"Module._compile (module.js:439:25)",
"Object.Module._extensions..js (module.js:474:10)",
"Module.load (module.js:356:32)",
"Function.Module._load (module.js:312:12)",
"Module.require (module.js:364:17)",
"require (module.js:380:17)"
]
}
My code is here. I have a feeling the problem is somewhere in lines 84-106 because that's where I did most of my work.
Thanks for any assistance!

The code below should work, just un-comment the todo I added. You had a couple of missing braces and I switched to a different http request lib that is included with AWS lambda by default. I also change the flow to make it simpler for me to test, so now it doesn't re-prompt it just tells you the latest bit coin price.
var https = require('https');
// Route the incoming request based on type (LaunchRequest, IntentRequest,
// etc.) The JSON body of the request is provided in the event parameter.
exports.handler = function (event, context) {
try {
console.log("event.session.application.applicationId=" + event.session.application.applicationId);
/**
* Uncomment this if statement and populate with your skill's application ID to
* prevent someone else from configuring a skill that sends requests to this function.
*/
// TODO add this back in for your app
// if (event.session.application.applicationId !== "amzn1.echo-sdk-ams.app.") {
// context.fail("Invalid Application ID");
// }
if (event.session.new) {
onSessionStarted({requestId: event.request.requestId}, event.session);
}
if (event.request.type === "LaunchRequest") {
onLaunch(event.request,
event.session,
function callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === "IntentRequest") {
onIntent(event.request,
event.session,
function callback(sessionAttributes, speechletResponse) {
context.succeed(buildResponse(sessionAttributes, speechletResponse));
});
} else if (event.request.type === "SessionEndedRequest") {
onSessionEnded(event.request, event.session);
context.succeed();
}
} catch (e) {
context.fail("Exception: " + e);
}
};
/**
* Called when the session starts.
*/
function onSessionStarted(sessionStartedRequest, session) {
console.log("onSessionStarted requestId=" + sessionStartedRequest.requestId
+ ", sessionId=" + session.sessionId);
}
/**
* Called when the user launches the skill without specifying what they want.
*/
function onLaunch(launchRequest, session, callback) {
console.log("onLaunch requestId=" + launchRequest.requestId
+ ", sessionId=" + session.sessionId);
// Dispatch to your skill's launch.
getWelcomeResponse(callback);
}
/**
* Called when the user specifies an intent for this skill.
*/
function onIntent(intentRequest, session, callback) {
console.log("onIntent requestId=" + intentRequest.requestId
+ ", sessionId=" + session.sessionId);
getWelcomeResponse(callback);
}
/**
* Called when the user ends the session.
* Is not called when the skill returns shouldEndSession=true.
*/
function onSessionEnded(sessionEndedRequest, session) {
console.log("onSessionEnded requestId=" + sessionEndedRequest.requestId
+ ", sessionId=" + session.sessionId);
// Add cleanup logic here
}
// --------------- Functions that control the skill's behavior -----------------------
function getWelcomeResponse(callback) {
// If we wanted to initialize the session to have some attributes we could add those here.
var sessionAttributes = {};
var cardTitle = "Bitcoin Price";
var speechOutput = "Welcome to the Bitcoin Price skill, "
var repromptText = ''
var shouldEndSession = true;
var options = {
host: 'btc-e.com',
port: 443,
path: '/api/2/btc_usd/ticker',
method: 'GET'
};
var req = https.request(options, function(res) {
var body = '';
console.log('Status:', res.statusCode);
console.log('Headers:', JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function(chunk) {
body += chunk;
});
res.on('end', function() {
console.log('Successfully processed HTTPS response');
body = JSON.parse(body);
console.log(body);
console.log('last price = ' + body.ticker.last);
speechOutput += "The last price for bitcoin was : " + body.ticker.last;
callback(sessionAttributes,
buildSpeechletResponse(cardTitle, speechOutput, repromptText, shouldEndSession));
});
});
req.end();
}
// --------------- Helpers that build all of the responses -----------------------
function buildSpeechletResponse(title, output, repromptText, shouldEndSession) {
return {
outputSpeech: {
type: "PlainText",
text: output
},
card: {
type: "Simple",
title: "SessionSpeechlet - " + title,
content: "SessionSpeechlet - " + output
},
reprompt: {
outputSpeech: {
type: "PlainText",
text: repromptText
}
},
shouldEndSession: shouldEndSession
}
}
function buildResponse(sessionAttributes, speechletResponse) {
return {
version: "1.0",
sessionAttributes: sessionAttributes,
response: speechletResponse
}
}

Related

How to resolve 403 error with Service Account and Google Drive API

I'm trying to write a client-side JS script that will fetch images from my gDrive to display on a website using a service account. I created the service account and added and enabled the google Drive API for the project. But when I run the script, I'm getting a 403 error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. I think it has to do with permissions or scopes maybe? I've looked at several other stack overflows and can't seem to figure it out.
Getting a 403 - Forbidden for Google Service Account
Google Drive service account returns 403 usageLimits
Some of them mention adding roles or scopes, but I can't figure out how to add them or which ones I need to add. Is a GSuite account mandatory? It sounds like I would need to go into the GSuite admin console to add the scopes? I would like to not have to sign up for an account, as it's not free. Any help would be appreciated. My code looks like the following:
function gDrive() {
function init(callback) {
authorizeClient(getJWT()).then(function(token) {
loadClient(token, callback);
});
}
/* Retrieve a signed JWT */
function getJWT() {
// Prepare header, payload, and key
let oHeader = {
"alg": "RS256",
"typ": "JWT"
};
let sHeader = JSON.stringify(oHeader);
let oPayload = {
"iss": "SERVICE ACCOUNT EMAIL",
"sub": "SERVICE ACCOUNT EMAIL",
"aud": "https://www.googleapis.com/oauth2/v3/token",
"iat": KJUR.jws.IntDate.getNow(),
"exp": KJUR.jws.IntDate.get("now + 1hour"),
"scope": "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.metadata https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/drive.photos.readonly https://www.googleapis.com/auth/drive.readonly"
};
let sPayload = JSON.stringify(oPayload);
let privKey = "-----BEGIN PRIVATE KEY-----BLAH BLAH BLAH\n-----END PRIVATE KEY-----\n";
// Sign JWT
return signedJWS = KJUR.jws.JWS.sign(null, sHeader, sPayload, privKey);
}
/* Http POST to Google Auth api */
function authorizeClient(JWS) {
// Request access token
const url = "https://www.googleapis.com/oauth2/v3/token";
let encodedData = "";
let encodedDataPairs = [];
encodedDataPairs.push(encodeURIComponent("grant_type") + '=' + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer"));
encodedDataPairs.push(encodeURIComponent("assertion") + '=' + encodeURIComponent(JWS));
encodedData = encodedDataPairs.join('&').replace(/%20/g, '+');
const params = {
headers: {"content-type":"application/x-www-form-urlencoded"},
body: encodedData,
method: "POST"
};
return fetch(url, params).then(accessTokenSucces).then(returnToken).catch(accessTokenFailed);
}
function accessTokenSucces(data) {
console.log("Retrieved access token");
return data.json();
}
function returnToken(resp) {
return resp.access_token;
}
function accessTokenFailed(error) {
console.log("Requesting access token failed: " + error);
}
function loadClient(accessToken, callback) {
gapi.load('client', function() {
console.log("loading client");
gapi.client.setToken(accessToken);
console.log("set access token");
return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest").then(clientLoadSuccessful).then(callback).catch(clientLoadFailed);
})
}
function clientLoadSuccessful() {
console.log("Client loaded");
return Promise.resolve();
}
function clientLoadFailed(error) {
console.log("Loading Client failed: " + error);
return Promise.reject();
}
function fetchAllImages(fileName, chapter, callback) {
console.log("fetching images");
let initialRequest = gapi.client.drive.files.list({"q": "mimeType contains \"image\" and name contains '"
+ fileName + "_ch" + chapter + "'"});
retrievePageOfFiles(initialRequest, [], fileName, chapter);
function retrievePageOfFiles(request, result) {
request.execute(function(resp) {
result = result.concat(resp.files);
let nextPageToken = resp.nextPageToken;
if (nextPageToken) {
request = gapi.client.drive.files.list({
"pageToken": nextPageToken,
"q": "mimeType contains \"image\" and name contains '" + fileName + "_ch" + chapter + "'"
});
retrievePageOfFiles(request, result);
} else {
console.log("Images retrieved");
callback(result);
}
}).catch(function(err) {
console.log("Could not retrieve images: " + err);
});
}
}
return {
init: init,
fetchAllImages: fetchAllImages
};
}
gDrive().init(runApp);
function runApp() {
console.log("Running App");
gDrive().fetchAllImages("FILENAME", "1", imageCallback);
}
function imageCallback(data) {
console.log("Images Retrieved!");
console.log(data);
}
When your script is run, the error of Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. occurs.
You want to remove this error.
If my understanding is correct, how about this modification? I think that the access token retrieved with your script can be used. So please modify your script as follows.
From:
gapi.client.setToken(accessToken);
To:
gapi.client.setToken({access_token: accessToken});
Reference:
gapi.client.setToken(tokenObject)
If this was not the direct solution of your issue, I apologize.

Managing subscription of push notification on client and server sides

I erase all my previous questions on how to use the code give into the documentation of workbox push notification to show you the solution I found more clearly.
before to show you the code, I will explain that I took long time to understand. You use normaly three files that work with service worker. In my case server.js, index.js and sw.js. When the browser get all the files it need to display your site, I also get the index.js file. This file start the service worker with navigator.serviceWorker.register('sw.js'). Then, it test if the user has already accepted to receive notification. At the end, it check if subscription exist or not and manage its.
The subscription part is very important and difficult to manage. With swRegistration.pushManager.subscribe() we will get an sub object. This object contains the endpoint, the auth and the p256th. Those informations are very important and we need to send to our server to store it into our database. the fetch() element do it. By this way, we will be able to send a notification to our tagerted user in the futur.
The last thing you need to know and how to create private and public Vapid keys. To generate it, display into your terminal the console.log that are below my privateVapidKey variable inside server.js. Then copy-paste both results into variable as I did server.js and alse copy-paste publicsVapidKey into index.js file.
server.js :
var express = require('express');
var app = express();
var https = require('https');
var fs = require('fs');
var webPush = require('web-push');
var bodyParser = require('body-parser');
https.createServer({
key: fs.readFileSync('key_localhost2.pem'),
cert: fs.readFileSync('cert_localhost2.pem'),
passphrase: 'localhost',
}, app).listen(8080);
//*****************************************************************
//-------------------------- TEMPLATES --------------------------
//*****************************************************************
//moteur de modèles ou de templates
app.set('view engine', 'ejs');
//*****************************************************************
//-------------------------- MIDDLEWARE --------------------------
//*****************************************************************
app
.use('/static', express.static(__dirname + '/public'))
.use(express.static(__dirname + '/public/js'))
.use(bodyParser.json());
//*****************************************************************
//--------------------------- ROUTES ------------------------------
//*****************************************************************
app.get('/', function (request, response) {
response.render('./pages/index.ejs');
});
var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs"
var privateVapidKey = "483sZs2cZUxSQegGKKOZXLl_b7_ywBF_qJO77gXFsHE"
//console.log('Publics keys : ' + vapidKeys.publicKey)
//console.log('Private key : ' + vapidKeys.privateKey)
webPush.setVapidDetails(
'mailto:localhost:8080',
publicVapidKey,
privateVapidKey
);
var pushSubscription;
app.post('/subscription_push_notification', function (req, resp) {
pushSubscription = req.body;
console.log(pushSubscription)
//I'm able to save this information into my database
endpointVal = req.body.endpoint;
authVal = req.body.keys.auth;
p256dhVal = req.body.keys.p256dh;
setTimeout(function () {
if (endpointVal) {
var payload = 'Here is a payload!';
webPush.sendNotification(
pushSubscription,
payload
).catch(function (err) {
console.log(err);
});
}
}, 2000)
resp.json({});
});
index.js :
window.addEventListener('load', function () {
//*********************************************************
// Start SW, permission notification, register subscribe
//*********************************************************
if ('serviceWorker' in navigator) {
//+++++++++++++++++++++++++++++
//Register Service worker
navigator.serviceWorker.register('sw.js')
.then(function (swRegistration) {
//Ask to notification permission
displayNotification();
var publicVapidKey = "BKwLqQWMQpLfSNGb-VXCsAPE1H5o7Oh3VxDiEIqWWOm2OdAoFPqr9K9WI7dKKtjYYHLTKm7tjJO04091pDXZiJs";
var applicationServerKey = urlBase64ToUint8Array(publicVapidKey);
//Manage push notifiaction
swRegistration.pushManager.getSubscription().then(function (sub) {
if (sub === null) {
// Update UI to ask user to register for Push
console.log('Not subscribed to push service!');
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
}).then(function (sub) {
// We have a subscription, update the database
console.log('Endpoint URL: ', sub.endpoint);
fetch('/subscription_push_notification', {
method: 'POST',
body : JSON.stringify(sub),
headers: {
'content-type':'application/json'
}
});
}).catch(function (e) {
if (Notification.permission === 'denied') {
console.warn('Permission for notifications was denied');
} else {
console.error('Unable to subscribe to push', e);
}
});
} else {
// We have a subscription, update the database
console.log('Subscription object: ', sub);
fetch('/subscription_push_notification', {
method: 'POST',
body : JSON.stringify(sub),
headers: {
'content-type':'application/json'
}
});
}
});
})
.catch(function (err) {
console.log('Service Worker registration failed: ', err);
})
}
//*********************************************************
// Function ask to notification permission
//*********************************************************
function displayNotification() {
if (Notification.permission === 'granted') {
//Mean, the notification is accepted.
console.log('Notification accepted...');
} else if (Notification.permission === "blocked" || Notification.permission === "denied") {
// the user has previously denied notification. Can't reprompt.
console.log('Notification blocked...');
} else {
// show a prompt to the user
console.log('Prompt to accept notification');
Notification.requestPermission();
}
}
//*********************************************************
// Transform public Vapid key
//*********************************************************
function urlBase64ToUint8Array(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4);
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
const rawData = window.atob(base64);
const outputArray = new Uint8Array(rawData.length);
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
});
sw.js :
importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.4.1/workbox-sw.js');
if (workbox) {
console.log(`Yay! Workbox is loaded 🎉`);
} else {
console.log(`Boo! Workbox didn't load 😬`);
}
//*********************************************************
// Save file from site to work in offline mode
//*********************************************************
workbox.precaching.precacheAndRoute([
{ url: '/', revision: '383676' },
{ url: '/static/css/style.css', revision: '383677' },
{ url: '/static/js/index.js', revision: '383678' },
]);
//*********************************************************
// The notification click event
//*********************************************************
//Inform when the notification close/hide from the window
self.addEventListener('notificationclick', function (e) {
console.log('notification was clicked')
var notification = e.notification;
var action = e.action;
if (action === 'close') {
notification.close();
} else {
clients.openWindow('https://www.google.fr');
};
});
//*********************************************************
// Handling the push event in the service worker
//*********************************************************
self.addEventListener('push', function (e) {
console.log('Hi man !!!')
var options = {
body: e.data.text(),
icon: '/static/img/logo_menu.png',
vibrate: [100, 50, 100],
data: {
dateOfArrival: Date.now(),
primaryKey: '2'
},
};
e.waitUntil(
self.registration.showNotification('Hello world!', options)
);
});

HTTP request callback not firing

I am making a skill for the Amazon Echo. In my handlers, I have an intent (SelectGardenIntent) that obtains the user_id (needed for following HTTP requests) from the access token successfully, as well as a variable called gardenNumber which is a slot value. To complete the request, I need two other values, the garden_id and the dev_id. I use this gardenNumber and pass it into a function called getGardenId, which will assign the one of the data from the HTTP request to the variable garden_id I have defined in index.js. There are no issues with user_id and gardenNumber. When the function is run, there are no errors from the request, but the callback function with the response is also not executed. The user_id, "about to enter request", and "req done" are correctly logged when tested, but the other log statements in the callback function are not since it is not run. The result is that garden_id is undefined. dev_id is obtained in another method that depends on this garden_id, so dev_id is also undefined. Please help me on this issue. I have pasted the relevant code below.
...
var user_id, garden_id, dev_id;
...
function getGardenId (gardenNumber) {
console.log(user_id);
var path = '/api/rest/client/getgardeninfo?&userid=' + user_id;
var options = {
hostname: server_ip,
port: 80,
path: path,
method: 'GET'
}
console.log("about to enter request");
var req = http.request(options, (res) => {
console.log('entered request');
if (res.statusCode === 200) {
console.log('successful request');
res.setEncoding('utf8');
var body = "";
res.on('data', (chunk) => {
console.log('adding data');
body += chunk.toString();
});
res.on('end', () => {
var obj = JSON.parse(body);
console.log('successfully parsed');
if (obj.error === 200) {
console.log('##gardenid successfully obtained');
garden_id = obj.data[gardenNumber - 1].id;
} else {
console.log("parsing error");
}
});
} else {
console.log("failed request");
}
}); } catch(e) {
console.log("ERROR");
}
req.on('error', (e) => {
console.error(`problem with request: ${e.message}`);
});
req.on('finish', () => {
console.log('ended');
})
req.end();
console.log("req done");
}
...
var handlers = {
...
'SelectGardenIntent': function () {
//var filledSlots = delegateSlotCollection.call(this);
var gardenNumber = this.event.request.intent.slots.Garden.value;
user_id = this.event.session.user.accessToken;
getGardenId(gardenNumber);
getDevId(garden_id);
this.emit(':tell', `OK, garden ${gardenNumber} selected, user id is ${user_id}, garden id is ${garden_id}, device id is ${dev_id}`);
}
...
}
You'd better use npm request to make calls.
request.get({
url: 'http://' + server_ip + '/api/rest/client/getgardeninfo?&userid=' + user_id
}, function (err, res, body) {
console.log(body);
})

"TypeError: Cannot read property 's' of undefined". What is the meaning of this in agenda.js?

This is the stack trace: This happens when I run the server.js file in my project. Also I couldn't find any explanation on the web. Can someone help with this error please?
E:\users\ashane\documents\visual studio 2015\Projects\ShowTracker\ShowTracker\node_modules\agenda\lib\agenda.js:341
if ( this._mdb.s.topology.connections().length === 0 ) { ^
TypeError: Cannot read property 's' of undefined
at Agenda._findAndLockNextJob (E:\users\ashane\documents\visual studio 2015\Projects\ShowTracker\ShowTracker\node_modules\agenda\lib\agenda.js:341:17) at jobQueueFilling (E:\users\ashane\documents\visual studio 2015\Projects\ShowTracker\ShowTracker\node_modules\agenda\lib\agenda.js:420:10) at processJobs (E:\users\ashane\documents\visual studio 2015\Projects\ShowTracker\ShowTracker\node_modules\agenda\lib\agenda.js:404:7)
at doNTCallback0 (node.js:417:9)
at process._tickCallback (node.js:346:13)
at Function.Module.runMain (module.js:469:11)
at startup (node.js:134:18)
at node.js:961:3
These are the only codes that are using angenda and "s" < as a string
var mongoConnectionString = "mongodb://127.0.0.1/agenda";
var agenda = require('agenda')({ db: { address: mongoConnectionString } });
var sugar = require('sugar');
var nodemailer = require('nodemailer');
// define an agenda job called send email alert.
agenda.define('send email alert', function (job, done) {
// what should happen when send email alert job is dispatched.
// When this job runs, name of the show will be passed in as an optional data object.
// Since we are not storing the entire user document in subscribers array (only references),
// we have to use Mongoose’s populate method.
Show.findOne({ name: job.attrs.data }).populate('subscribers').exec(function (err, show) {
var emails = show.subscribers.map(function (user) {
return user.email;
});
var upcomingEpisode = show.episodes.filter(function (episode) {
return new Date(episode.firstAired) > new Date();
})[0];
var smtpTransport = nodemailer.createTransport('SMTP', {
service: 'SendGrid',
auth: { user: 'hslogin', pass: 'hspassword00' }
});
// standard Nodemailer boilerplate for sending emails.
var mailOptions = {
from: 'Fred Foo ✔ <foo#blurdybloop.com>',
to: emails.join(','),
subject: show.name + ' is starting soon!',
text: show.name + ' starts in less than 2 hours on ' + show.network + '.\n\n' +
'Episode ' + upcomingEpisode.episodeNumber + ' Overview\n\n' + upcomingEpisode.overview
};
smtpTransport.sendMail(mailOptions, function (error, response) {
console.log('Message sent: ' + response.message);
smtpTransport.close();
done();
});
});
});
agenda.start();
agenda.on('start', function (job) {
console.log("Job %s starting", job.attrs.name);
});
agenda.on('complete', function (job) {
console.log("Job %s finished", job.attrs.name);
});
it works when .on('ready') function is present. Here is my example.
var Agenda = require('agenda');
var agenda = new Agenda({db: { address: 'localhost:27017/servicebox-dev'}});
matcher.matchProviders(agenda);
agenda.on('ready', function() {
agenda.every('5 seconds', 'match providers');
agenda.start();
});
In agenda.js, at line if ( this._mdb.s.topology.connections().length === 0 ), this._mdb is undefined.
The method Agent.prototype.database assigns to _mdb the returned db object from MongoClient.connect. So my guess is that the connect operation fails. Are you sure of your connection string?

Opentok unable to connect to session

This is specific to the Opentok API. I'm quite new to javascript and struggling to get this all to work nicely.
Here's a link to the docs if you need it:
https://tokbox.com/developer/guides/
My error is:
signal error (500): Unable to send signal - you are not connected to the session.
My html file looks like this:
var apiKey = 45317102;
var sessionID = "#{#session.session_id}";
if (OT.checkSystemRequirements() == 1) {
var session = OT.initSession(apiKey, sessionID);
} else {
// the client does not support WebRTC
console.log('does not support WebRTC');
}
var token = "#{#token.token}";
var publisher;
var publisherOptions = {
width: 600,
height: 400,
name: 'Publisher',
// publishAudio: true,
// publishVideo: false
}
var subscriberOptions = {
width: 300,
height: 200,
name: 'Subscriber'
}
// for publisher
session.connect(token, function(error) {
if (error) {
console.log(error.message);
} else {
session.publish('myPublisherDiv', publisherOptions);
console.log('Publishing a stream.');
}
});
// for subscribers
session.on({
streamCreated: function(event) {
session.subscribe(event.stream, 'subscribersDiv', subscriberOptions);
console.log("New stream in the session: " + event.stream.streamId);
}
});
// check if the user is a moderator
if (session.capabilities.forceDisconnect == 1) {
console.log('you can moderate.')
} else {
console.log('you cant moderate');
}
session.signal(
{
data:"hello"
},
function(error) {
if (error) {
console.log("signal error ("
+ error.code
+ "): " + error.message);
} else {
console.log("signal sent.");
}
}
);
and my backend (ruby / rails) controller looks like this:
def create
session = OPENTOK.create_session media_mode: :routed
session_id = session.session_id
#session = Session.new(session_id: session_id)
if #session.save
redirect_to #session
else
render 'new'
end
end
def show
#session = Session.find(params[:id])
unless params[:id].blank?
s = Session.find(params[:id])
token = OPENTOK.generate_token s.session_id
#token = Token.create(session_id: s.id, token: token, active: true)
#token.save
end
end
now I'm not able to make the person who creates the session a moderator (ability to remove others) and it seems like I'm in-fact even unable to connect to the session. Even though when I run it I'm able to have 2 people in the same session at the same time.
Does anybody know what's happening (or more likely what I'm missing from my code)?

Categories