By default all tokens generated with the Twilio helper libraries expire after one hour. But you should configure this expiration to be as short as possible for your application.
I am trying to generate a new token each time a user attempts a new connection and try to setup Twilio device. But it creates new device each time. So all Twilio device get incoming call and i can see multiple notification for that. Multiple connections created an dmultiple dtmf sent. I want only one twilio device with fresh token.
Twilio.Device.destroy() method is there but it is not working. What are other option do I have?
How to release/destroy/stop/delete Twilio.Device?
After saving credentials globalTwilioSagaSetup() called and after 58min of that again token is generated and Twilio.Device setup is done.
function globalTwilioSagaSetup()
{
// Get Twilio credentials
// Get Twilio Token
// Setup Twilio Device
// For token re-generation before expire. 58min
setInterval(function(){globalTwilioSagaSetup();},3480000);
}
I've had similar issue although in current version of twilio lib (i.e. 1.2). The thing is that once setup is called ready event is fired but only after first call to the setup method. It means that even if one will initialize device with new token there will be problems with establishing new connection. Therefore calling Twilio.Device.destroy() then setup and then connect (via ready event) solved that issue for me. Here is an example:
srv.connectToTwilio = () => $q((resolve, reject) => {
var connection;
try {
connection = Twilio.Device.connect();
} catch (err) {
$log.debug('Device.connect(): throw', err);
}
if (connection) {
try {
connection.accept(() => {
$log.debug(`Twilio connection.accept.`);
resolve();
});
} catch (err) {
$log.debug('connection.accept(): throw', err);
}
} else {
reject(`Device.connect() did not return connection`);
}
});
srv.connect = (token) => {
return srv.setToken(token).then(() => srv.connectToTwilio());
};
srv.disconnect = () => {
shouldBeConnected = false;
try {
Twilio.Device.activeConnection().disconnect();
} catch (error) {
$log.debug(error);
} finally {
Twilio.Device.destroy();
}
$log.debug(`Twilio disconnect.`);
};
Related
for a while now I am stuck, trying to listen to the event where the agent sends a reply to the ticket. I have tried listening to ticket.comments.changed and ticket.conversation.changed but have not been successful.
I can't use the ticket.submit.[done|fail|always] or ticket.save because I don't have a way of knowing if it is the event I want or is being called with another event.
Maybe someone who knows of a configuration or some way that would allow me to do this, I would be very grateful.
You can configure triggers and webhooks to be added to your app as requirements. If you must use a ticket_sidebar app, you can listen to the following events:
var client = ZAFClient.init();
client.on('ticket.comments.changed', (e) => {
// Here is the latest comment
let comment = e[0];
console.log(comment);
// Check author role
console.log((comment.author.role !== "end-user") ? "Comment made by agent" : "Comment made by end user");
// Get ticket object if needed
client.get('ticket').then(
(res) => {
// Send ticket payload to my backend
},
(err) => {
console.error(err);
}
)
});
client.on('ticket.status.changed', (e) => {
// Here is the new status
console.log("Status changed to", e);
// Get ticket object if needed
client.get('ticket').then(
(res) => {
// Send ticket payload to my backend
},
(err) => {
console.error(err);
}
)
});
I am getting the event emitter leak after using my code 10 times essentially. I understand the default of event emitter auto sending out a warning in the console. My question is what in this code is directly creating the event listeners? Is it poor coding on my part or is it just how the websockets are stacked onto each other?
I'll explain the code a bit. I have one websocket within another and I figured it would serve the data to a web page essentially flowing from Twitch to a localhost site. However, if I use the keywords more than 10 times, I get the error. I do not understand enough about WebSockets to really understand why my code creates a new listener with each msg.text received so anyone with a bit more understanding please help!
I believe me issue to be similar to this though I am having a hard time conceptualizing my own code here
const { paintballShot } = require('./JavaScript/paintballGunFire');
const { readPin } = require('./JavaScript/readPin');
const ws = require('ws');
const express = require('express');
const app = express();
//CONNECT TO TWITCH
let client = new ChatClient({
connection: {
type: "websocket",
secure: true,
}
});
//connected?
client.on("ready", () => console.log("Successfully connected to chat"));
client.on("close", (error) => {
if (error != null) {
console.error("Client closed due to error", error);
}
});
//create headless websocket
const wsServer = new ws.Server({ noServer: true });
wsServer.on('connection', function connection(socket) {
//call other websocket connected to Twitch from inside the new websocket
client.on("PRIVMSG", (msg, error) => {
if (msg.messageText === "right") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "left") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
}
if (msg.messageText === "fire") {
socket.send(JSON.stringify(`${msg.displayName}: ${msg.messageText}`));
paintballShot();
}
if (msg.messageText === "pin") {
readPin();
}
process.on('uncaughtException', function (err) {
console.log(err);
});
});
client.connect();
client.join("channel");
socket.on('message', message => console.log(message));
});
// `server` is a vanilla Node.js HTTP server
const server = app.listen(3000);
server.on('upgrade', (request, socket, head) => {
wsServer.handleUpgrade(request, socket, head, socket => {
wsServer.emit('connection', socket, request);
});
});
process.on('uncaughtException', function (err) {
console.log(err);
});
To wrap this up, the library I am using (Dank TwitchIRC) does have a connection rate limiter that seems to work if you add it to your chat client in the beginning. If I set it low enough, depending on the messages received from Twitch, it will end connections just as fast, meaning no memory leak.
I'm currently trying to implement in my Angular app the connection to Strava API.
To resume quickly:
User clicks on a button to connect to Strava
It is redirected to Strava for authentication(using PKCE)
Strava redirects to my app with a code
In the ngoninit I'm checking for route params and if I have the code, I launch two promises chained: the first one to get the Access Token from Strava then the recording into a DB(Firebase).
The problem is that sometimes the data is recorded in firebase and sometimes it is not. The behavior is not systematic. Strange thing is that I go into my postNewToken everytime because the console logs it.
If I just record to firebase (without strava token request) in ngOnInit(), it is created in 100% of the cases.
If I have a button that launches the token request and record into firebase, it seems to work everytime.
I have no idea how to solve it. It seems more a question of chaining promises into ngOnInit but I have no idea even how to bypass it.
The code from my component:
ngOnInit() {
const stravaCode = this.route.snapshot.queryParamMap.get('code');
if (stravaCode !== undefined) {
this.stravaService.handleStravaAuthorizationCode(stravaCode);
}
And in the service associated:
// Handle Strava Code received
handleStravaAuthorizationCode(authorizationCode: string) {
this.getStravaToken(authorizationCode).then(res => {
this.postNewToken(res).then(res => {
this.router.navigate(['encoding']);
});
});
}
// Get Strava access token to make the requests to the API -> only done once
getStravaToken(authorizationCode: string){
if (authorizationCode !== undefined){
console.log('Authorization code: ' + authorizationCode);
const data = {
client_id: environment.strava.client_id,
client_secret: environment.strava.client_secret,
code: authorizationCode,
grant_type: 'authorization_code'
};
return this.http.post<StravaToken>(this.stravaTokenURL, data)
.pipe(catchError(this.errorService.handleHttpError)).toPromise();
}
}
postNewToken(stravaToken: StravaToken) {
if (this.authService.isLoggedIn) {
console.log('Recording strava token into Firebase');
console.log(stravaToken);
return this.afs.collection('strava_tokens')
.add(stravaToken).then(res => console.log(res), err => console.log(err));
} else {
return Promise.reject(new Error('No User Logged In!'));
}
}
Finally, I understood.
I simply was not waiting for the connection to firebase to be established. So, I could not post any new data because I was not authenticated.
I'm building my first FB Messenger chat bot using Wit as the NLP engine. All my services are connected and seem to be working on the surface, but when I look at my Heroku logs it seems that my bot's responses are being sent back to Wit to be parsed as well as user inputted messages. This is obviously causing issues further through my conversation flow when it comes time to trigger actions.
How do I make it so that my bot only parses user input, then responds appropriately according to my story in Wit?
Messenger window:
Relevant part of my Wit conversation flow:
My logs:
As far as I can tell, this is the important code:
var actions = {
say (sessionId, context, message, cb) {
// Bot testing mode, run cb() and return
if (require.main === module) {
cb()
return
}
console.log('WIT HAS A CONTEXT:', context)
if (checkURL(message)) {
FB.newMessage(context._fbid_, message, true)
} else {
FB.newMessage(context._fbid_, message)
}
cb()
},
...
}
///
var read = function (sender, message, reply) {
console.log('READING LOG AAAAAAAAAAAAAAAAAAAAAA')
var sessionId = findOrCreateSession(sender)
console.log('READING LOG BBBBBBBBBBBBBBBBBBBBBB')
console.log(message)
// Let's forward the message to the Wit.ai bot engine
// This will run all actions until there are no more actions left to do
wit.runActions(
sessionId, // the user's current session by id
message, // the user's message
sessions[sessionId].context, // the user's session state
function (error, context) { // callback
console.log('READING LOG CCCCCCCCCCCCCC')
if (error) {
console.log('oops!', error)
} else {
// Wit.ai ran all the actions
// Now it needs more messages
console.log('READING LOG DDDDDDDDDDDDDDDD')
console.log('Waiting for further messages')
// Updating the user's current session state
sessions[sessionId].context = context
console.log('READING LOG EEEEEEEEEEEEEEEE')
}
})
}
///
app.post('/webhooks', function (req, res) {
var entry = FB.getMessageEntry(req.body)
// IS THE ENTRY A VALID MESSAGE?
if (entry && entry.message) {
if (entry.message.attachments) {
// NOT SMART ENOUGH FOR ATTACHMENTS YET
FB.newMessage(entry.sender.id, "That's interesting!")
} else {
// SEND TO BOT FOR PROCESSING
console.log('SENDING TO BOT FOR PROCESSING XXXXX')
Bot.read(entry.sender.id, entry.message.text, function (sender, reply) {
FB.newMessage(sender, reply)
return
})
console.log('SENDING TO BOT FOR PROCESSING YYYYY')
}
}
res.sendStatus(200)
})
When you create your Facebook messenger app, one of the webhooks events is message_echoes.
Make sure you you opt it out message_echoes for not receiving your own bot messages.
I used the 'is_echo' : true to discern wits messages from others and it's been working.
if (event.message.is_echo) {
console.log(`This sender is the wit bot.`);
return;
}
I am having trouble using the Parse Server JS SDK to edit and save a user.
I am signing in, logging in and retrieving the user just fine, I can call without exception user.set and add/edit any field I want, but when I try to save, even when using the masterKey, I get Error 206: Can t modify user <id>.
I also have tried to use save to direcly set the fields, same result.
A interesting thing is that in the DB, the User's Schema get updated with the new fields and types.
Here is my update function:
function login(user, callback) {
let username = user.email,
password = user.password;
Parse.User.logIn(username, password).then(
(user) => {
if(!user) {
callback('No user found');
} else {
callback(null, user);
}
},
(error) => {
callback(error.message, null);
}
);
}
function update(user, callback) {
login(user, (error, user) => {
if(error) {
callback('Can t find user');
} else {
console.log('save');
console.log('Session token: ' + user.getSessionToken());
console.log('Master key: ' + Parse.masterKey);
user.set('user', 'set');
user.save({key: 'test'}, {useMasterKey: true}).then(
(test) => {
console.log('OK - ' + test);
callback();
}, (err) => {
console.log('ERR - ' + require('util').inspect(err));
callback(error.message);
}
);
}
});
}
And a exemple of the error:
update
save
Session token: r:c29b35a48d144f146838638f6cbed091
Master key: <my master key>
ERR- ParseError { code: 206, message: 'cannot modify user NPubttVAYv' }
How can I save correctly my edited user?
I had the exact same problem when using Parse Server with migrated data from an existing app.
The app was created before March 2015 when the new Enhanced Sessions was introduced. The app was still using legacy session tokens and the migration to the new revocable sessions system was never made. Parse Server requires revocable sessions tokens and will fail when encountering legacy session tokens.
In the app settings panel, the Require revocable sessions setting was not enabled before the migration and users sessions were not migrated to the new system when switching to Parse Server. The result when trying to edit a user was a 400 Bad Request with the message cannot modify user xxxxx (Code: 206).
To fix the issue, I followed the Session Migration Tutorial provided by Parse which explain how to upgrade from legacy session tokens to revocable sessions. Multiple methods are described depending on your needs like enableRevocableSession() to enable these sessions on a mobile app, if you're only having a web app, you can enforce that any API requests with a legacy session token to return an invalid session token error, etc.
You should also check if you're handling invalid session token error correctly during the migration to prompt the user to login again and therefore obtain a new session token.
I had the same error and neither useMasterKey nor sessionToken worked for me either. :(
Here's my code:
console.log("### attempt 1 sessionToken: " + request.user.getSessionToken());
var p1 = plan.save();
var p2 = request.user.save(null, {sessionToken: request.user.getSessionToken()});
return Parse.Promise.when([p1, p2]).then(function(savedPlan) {
...
}
I see the matching session token in log output:
2016-08-21T00:19:03.318662+00:00 app[web.1]: ### attempt 1 sessionToken: r:506deaeecf8a0299c9a4678ccac47126
my user object has the correct ACL values:
"ACL":{"*":{"read":true},"PC7AuAVDLY":{"read":true,"write":true}}
I also see a bunch of beforeSave and afterSave logs with user being "undefined". not sure whether that's related.
beforeSave triggered for _User for user undefined:
I'm running latest parser-server version 2.2.18 on Heroku (tried it on AWS and results are the same)
function login(logInfo, callback) {
let username = logInfo.email,
password = logInfo.password;
Parse.User.logIn(username, password).then(
(user) => {
if(!user) {
callback('No user found');
} else {
callback(null, user);
}
},
(error) => {
callback(error.message, null);
}
);
}
function update(userInfo, data, callback) {
login(userInfo, (error, user) => {
if(error) {
callback('Can t find user');
} else {
getUpdatedData(user.get('data'), data, (error, updateData) => {
if(error) {
callback(error);
} else {
user.save({data: updateData}, /*{useMasterKey: true}*/ {sessionToken: user.get("sessionToken")}).then(
(test) => {
callback();
}, (err) => {
callback(error.message);
}
);
}
});
}
});
}
For some reason, retrying to use sessionToken worked.
This is not how asynchronous functions work in JavaScript. When createUser returns, the user has not yet been created. Calling user.save kicks off the save process, but it isn't finished until the success or error callback has been executed. You should have createUser take another callback as an argument, and call it from the user.save success callback.
Also, you can't create a user with save. You need to use Parse.User.signUp.
The function returns long before success or error is called.