Change person's presence state using vLine API - vline

How do I change a person's status (setPresenceState) after the user accepts a call?
I need to set the state to "busy" for the person.
I think I can set the presence to busy when the "enterState:active" event fires, but how exactly do I do that?

In our documentation, we say that we automatically set the presence state to 'busy', when on a call, but looking through our code, it looks like we're currently not doing that. I'll fix that, but in the meantime I'll give an example of how you can do this yourself (in case you wanted to have some other behavior).
The general idea is to set the presence state to busy when the vline.MediaSession goes into the active state. In this example, client is assumed to be the logged-in vline.Client and session is assumed to be the vline.Session returned after logging in.
client.on('add:mediaSession', function(event) {
var mediaSession = event.target;
mediaSession.on('enterState:active', function() {
session.setPresence('busy');
}, this);
mediaSession.on('enterState:closed', function() {
session.setPresence('online');
}, this);
}, this);

All will work fine, and when u send a videocall, nobody can send a other video call

The PresenceStates "busy" don't work, anything u want to do..
I use the "do_not_disturb" PresenceStates, instead of, and reset the state of "do_not_disturb" , even if the media session is 'disconnected' or broke by client or person.
You get it?
add this code instead of :
//----------------------------------------------------------------
client.on('add:mediaSession', function(event) {
var mediaSession = event.target;
mediaSession.on('enterState:active', function() {
session.setPresence('do_not_disturb');
}, this);
mediaSession.on('enterState:closed', function() {
session.setPresence('online');
}, this);
mediaSession.on('enterState:outgoing', function() {
session.setPresence('do_not_disturb');
}, this);
mediaSession.on('enterState:incoming', function() {
session.setPresence('do_not_disturb');
}, this);
mediaSession.on('enterState:disconnected', function() {
session.setPresence('online');
}, this);
}, this);
//----------------------------------------------------------------
To reset the state of 'do_not_disturb', what event happen, and even if client or person, have broke the session, just add this code after :
// fetch person object associated with username:
session.getPerson(userId).done(function(person) {
session.setPresence('online');
( vline.MediaSession is assumed to be into the active state.
session is assumed to be the vline.Session returned after logging in.)

Related

Is there a way to make bots aware of what page they are on?

I have a chatbot that will eventually be deployed on multiple websites, and there are a number or variables that need to change based on the site (e.g. language, QnA Database, Dialog, etc.). I'd like to do this with a single bot, and just pass a variable so that it knows which page it is being rendered on (for a simple example, let's assume country pages: us, fr, de, etc.). I have been unsuccessful in passing this information to the bot.
Ideally this would be before the welcome message fires, but I can't even get it to send at all. I have a custom store set up:
const store = window.WebChat.createStore({}, function(dispatch) { return function(next) { return function(action) {
if (action.type === 'WEB_CHAT/SEND_MESSAGE') {
// Message sent by the user
PageTitleNotification.Off();
clearTimeout(interval);
} else if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' && action.payload.activity.name !== "inactive") {
// Message sent by the bot
clearInterval(interval);
interval = setTimeout(function() {
// Change title to flash the page
PageTitleNotification.On('Are you still there?');
// Notify bot the user has been inactive
dispatch.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'inactive',
value: ''
}
});
}, 300000)
}
return next(action);
}}});
But for my use case I don't think what's in there actually matters, only that it is defined. The functions here just 1) clear an interval when the user sends a message and 2) set a new interval and send an inactivity message to the bot.
I also have a send message activity that is on a button click for a transcript. It looks like this:
document.querySelector('#transcriptButton').addEventListener('click', function() {
return store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: { text: 'Email me a transcript' }
});
/*return store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'siteContext',
value: 'eatonchatbot indexBackup.html'
}
});*/
});
This sends a "front channel" message (that I can see in the bot) to request a transcript, which kicks off a dialog. That works. The commented out section alludes to what I'm trying to do. I have a separate dispatch statement as shown below, which has the exact same SEND_EVENT code as is commented out above. The SEND_EVENT does work as expected when it keys off the button click.
Here is the additional code I added. This is the piece that is NOT working. What I want is, when the bot has been rendered (but ideally before the welcome message), send this siteContext event to the bot so that I know where the bot is being rendered. I do not get any activity in the bot with this code. I also tried replacing it with SEND_MESSAGE instead of SEND_EVENT in a sort of reverse test from above, but that didn't work either.
// Test setting site context
store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'siteContext',
value: 'eatonchatbot indexBackup.html'
}
});
/*store.dispatch({
type: 'WEB_CHAT/SEND_MESSAGE',
payload: {
text: 'eatonchatbot indexBackup.html'
}
});*/
It just occurred to me that this statement is probably running before the bot is rendered. So I put it in an interval and this DOES work. However, it does not fire the message until after the welcome message has been sent.
setTimeout(function() {
store.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'siteContext',
value: 'eatonchatbot indexBackup.html'
}
});
}, 5000);
So this kind of works, but if this siteContext value was needed to determine the language of the welcome message, this would obviously fail. So my main ask here is, is there a better way to try to pass in a siteContext value like this, or is there some way to ensure that the context is received and can be used by the bot before the welcome message fires? I do see that there is a locale setting in the renderWebChat method, but I can't figure out if and how I could access that in the bot, and besides it may not be granular enough depending on the business need. But it seems if I could send some sort of value in that renderWebChat object, that might avoid all of the other crazy stuff I'm trying to do.
With some help from #Hessel and this issue I found on GitHub, I was able to come up with a solution. Just setting the values being passed in via onEvent (which I am now using in place of onTurn to reduce an if statement) isn't good enough if you need to alter content in the welcome message (e.g. language, user name, or an altogether different message). The onMembersAdded still fires before the values can be set, at least if you're setting them in userState. The key is to set up separate welcome messages in onEvent for directline and onMembersAdded for all other channels (I didn't include webchat as in the example as I'm not sending any event for that channel).
Here is the onEvent function I used:
this.onEvent(async (context, next) => {
// Check for inactivity
if (context.activity.name && context.activity.name === 'inactive') {
await context.sendActivity({
text: 'Are you still there? Is there anything else I can help you with?',
name: 'inactive'
});
}
// Check for webchat/join event (directline conversation initiation)
if (context.activity.name && context.activity.name === 'webchat/join') {
const userData = await this.userDialogStateAccessor.get(context, {});
userData.siteContext = context.activity.value;
// Debug
console.log(`The current language is: ${userData.siteContext.language}`);
console.log(`The current page is: ${userData.siteContext.page}`);
//await context.sendActivity(`The current language is: ${userData.siteContext.language}`);
//await context.sendActivity(`The current page is: ${userData.siteContext.page}`);
if (!userData.accountNumber) {
const dc = await this.dialogs.createContext(context);
await dc.beginDialog(AUTH_DIALOG);
await this.conversationState.saveChanges(context);
await this.userState.saveChanges(context);
} else {
if (context.activity.channelId == 'msteams') {
var welcomeCard = CardHelper.GetMenuCardTeams(welcomeMessage,'Y','Y');
} else {
var welcomeCard = CardHelper.GetMenuCard(welcomeMessage,'Y','Y');
}
await context.sendActivity(welcomeCard);
this.appInsightsClient.trackEvent({name:'conversationStart', properties:{accountNumber:userData.accountNumber}});
}
await this.userState.saveChanges(context);
}
// By calling next() you ensure that the next BotHandler is run.
await next();
});
The event I used in the custom store is pretty much the same as above, except I updated it to pull in the most preferred language and current url (was hard coded above).
store = window.WebChat.createStore({}, function (dispatch) {
return function (next) {
return function (action) {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
dispatch.dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: {
language: navigator.languages[0],
page: window.location.href
}
}
});
}
return next(action);
};
};
});
If you have your renderWebChat method inside a function that you can call so that your bot doesn't automatically start (I have a floating icon that causes the bot to load onclick) this should go outside that function.

In socket.io, how do I differentiate between 2 triggers of the same event?

Suppose I have a simple event defined as
socket.on('event', function(data){
...
});
And if the client fires it two times, one after another
socket.emit('event'); //once
socket.emit('event'); //again
Is there a way to *inherently** differentiate between the two events?
*I don't want want to depend on data because that's just a client side variable, and could easily be tampered with. (right?)
For context, it's related to this question.
I would use sessionSockets to save data for each user on the server side.
sessionSockets.on('connection', function (err, socket, session) {
socket.on('event', function() {
if(!session.eventReceived) {
// manage event
// save event received in session
session.eventReceived = true;
session.save();
}
});
});

Should I define socket.on('... event outside the io.sockets.on('connection... scope?

I have various clients' sockets connect to my server and I need to define an event on each of them, but based on some logic, not unconditionally. Like:
for(i= 0; i<= this.users.length; i++) {
if (i=== actionUserOrdinal) {
io.sockets.socket(mySocketId).on('action', function(action) {...
but doing so it gets defined multiple times for some sockets during the course of running the app. And so, it gets invoked multiple times too (by the same trigger).
And if I define it the default way,
io.sockets.on('connection', function(socket) {
socket.on('action', function(data) {
...
I cannot access my main app logic's variables and such. Unless I make some things global.
One solution I thought of was to delete the event after it is triggered
for(i= 0; i<= this.users.length; i++) {
if (i=== actionUserOrdinal) {
thisocket = io.sockets.socket(mySocketId);
io.sockets.socket(mySocketId).on('action', function(action) {
delete thisocket._events.action;
(Thanks #ArdiVaba)
But I discover this is flaky and the event still gets fired twice sometimes.
Is there some other way to define the event such that it doesn't gets define more than once, by either defining it in my main app's logic itself, or by defining it in its default scope yet I still be able to access my main app's variables without going global?
Instead of defining different events possible for each user, listen for all events for all users and in the function verify if the user is allowed to use this event.
Use sessionSockets to store the type of user and his permissions
// checkPermission function check if user is allowed to do something
checkPermissions = function(function_name, session, callback) {
if(!session) {
callback(null);
return;
}
if(!session.user) {
callback(null);
return;
}
// If user is superuser, he has the right to do everything
if(!session.user.superuser) {
callback('allowed');
return;
}
// TODO Here check with user and function_name if user has the right
// to use this function
// use callback('allowed') if he is allowed
// use callback(null) if he is not allowed
}
sessionSockets.on('connection', function (err, socket, session) {
socket.on('event', function() {
checkPermission('event', session, function(r) {
if(r === 'allowed') {
// User is allowed
// Do your thing
} else {
// User is not allowed
// send error message to user ?
}
});
});
});

socket.io data seems to be sent multiple times(nodejs and craftyjs)

I am following this tutorial on making HTML5 games. I wanted to try and mix node in to make it multiplayer. I am using node.js(v0.10.4) on server and crafty.js on front end.
I am using socket.io to send and receive messages. For now it's just me(not multiple clients). The weird thing that happens is that the message that comes from the server seems to be sent multiple times. I turned on debug mode in socket.io but it only seems to be sending the data once, yet on the front end the data seems to be coming in, in multiples. I set an incrementor on the data and it seems as if the incrementor is not incrementing multiple times but instead I am getting multiple copies of the same data.
here's node code:
var http = require('http').createServer(handler),
static = require('node-static'),
io = require('socket.io').listen(http);
io.set('log level', 3);
http.listen(80);
//attach the socket to our server
var file = new static.Server(); //Create a file object so we can server the files in the correct folder
function handler(req, res) {
req.addListener('end', function() {
file.serve(req, res);
}).resume();
}
io.sockets.on('connection', function (socket) { //listen for any sockets that will come from the client
socket.on('collected', function(data) {
/**** here's where the data is being sent back to the client *****/
socket.emit('messageFromServer', { data: data.number });
});
});
and here's front end code:
//messenger entity
Crafty.c('SendRecieveMessages',{
count: 0,
sendMessageToServer : function() {
console.log('got a village');
/**** Here's where we send the message to the server ****/
socket.emit('collected', { village : "The message went to the server and back. it's collected", number : this.count });
this.count++;
},
recieveMessageFromServer : function() {
socket.on('messageFromServer', function(data) {
/*** This data seems to be coming back or logging multiple times? ***/
console.log(data);
});
}
});
Lastly here's a screenshot of the debug in process. As you can see number is not always incrementing, it almost looks like the data is getting stored. Thanks!
http://cl.ly/image/0i3H0q2P1X0S
It looks like every time you call Crafty.c, recieveMessageFromServer() is getting called too. Every time recieveMessageFromServer is invoked, it attaches an additional event listener on the socket. That's why the first time data comes back you get one copy, then the second time you get two, the third time you get three, and so on.
You either need to prevent recieveMessageFromServer from being called multiple times, or use removeListener or removeAllListeners to remove the previously attached listeners.
Thanks to #Bret Copeland for helping me figure this one out. As he pointed out, every time socket.on() is called, it seems to add another listener. To prevent this...
I declared a global variable:
I declared a variable as a property in my Game object(in craftyjs, so use whatever you want in your setup)
Game = {
//lots of other code here...
//need this to use later for socket.io
send_message : true
}
then edited my recieveMessageFromServer() function to check whether its ok to send the message or not:
recieveMessageFromServer : function() {
console.log('does this show up multiple times?');
/* Check whether the send_message is true before sending */
if (Game.send_message) {
socket.on('messageFromServer', function(data) {
console.log(data);
Game.send_message = false;
});
}
}

Backbonejs, "Object #<Object> has no method apply" when setting model attribute inside a Collections.each

I made and initialized my model with the "change:status" event like this
Box = Backbone.Model.extend({
initialize: function() {
this.on('change:status', this.changed, this);
},
changed: function() {
$('.changed').text('I changed'); // Testing if the 'change:status' is fired
}
});
My Box collections is setup this way
BoxList = Backbone.Collection.extend({
model: Box,
initialize: function() {
this.on('add', this.addOne, this);
socket.on('box-status-change', this.boxStatusChanged, this);
},
boxStatusChanged: function(box) {
Boxes.each(function(model) {
if(model.get('changed') == box.changed) {
model.set({status: 'changed'});
}
});
},
addOne: function.... // Some code removed
});
Boxes = new BoxList();
Checking in Chromes web developer tools, the attribute status was set to changed properly but an error Uncaught TypeError: Object #<Object> has no method 'apply' occured. The change:title event of the model was not fired. Is there something I miss when adding the event to the model?
By the way, I'm using the backbone-iosync.js for the Backbone.sync method...
Backbone uses an internal attribute called changed on models:
http://backbonejs.org/#Model-changed
changed model.changed
The changed property is the internal hash containing all the
attributes that have changed since the last "change" event was
triggered. Please do not update changed directly. Its state is
maintained internally by set and change. A copy of changed can be
acquired from changedAttributes.
Rename your callback to something else and that works
Box = Backbone.Model.extend({
initialize: function() {
this.on('change:status', this.changedState, this);
},
changedState: function() {
console.log('changed');
}
});
A Fiddle to reproduce your problem http://jsfiddle.net/NrTPk/ and a modified version http://jsfiddle.net/NrTPk/1/

Resources