Opentok | Get online users - opentok

This is my code for opentok connect. How to know when other user connected or disconnected to the session ? So i can populate my online friends list like social network site. Then i can initiate a chat with them.
function connect() {
OT.on("exception", exceptionHandler);
// Un-comment the following to set automatic logging:
OT.setLogLevel(OT.DEBUG);
if (!(OT.checkSystemRequirements())) {
alert("You don't have the minimum requirements to run this application.");
} else {
session = OT.initSession(sessionId); // Initialize session
session.connect(apiKey, token);
// Add event listeners to the session
session.on('sessionConnected', sessionConnectedHandler);
session.on('sessionDisconnected', sessionDisconnectedHandler);
session.on('connectionCreated', connectionCreatedHandler);
session.on('connectionDestroyed', connectionDestroyedHandler);
session.on('streamCreated', streamCreatedHandler);
session.on('streamDestroyed', streamDestroyedHandler);
session.on("signal", signalEventHandler);
}
}
function sessionConnectedHandler(event) {
// i am connected .... do something after connected
document.getElementById("User_name").innerHTML = user_name;
document.getElementById("disconnectLink").style.display = 'block';
//startPublishing();
}

The function connectionCreatedHandler will get called each time another user connects, and connectionDestroyedHandler will get called each time a user disconnects.
For a sample app that has a "Buddy List" like functionality, see Presence Kit. Demo: http://presencekit-php.herokuapp.com/

Related

Detect network changes in Xamarin Forms

I want to detect when the user is online or offline.
I am using CrossConnectivity package to detect connectivity changes.
I have to connect to VPN (Sonic Wall to be exact) in order to connect to my server.
My problem is this: When I am connecting to my server, I need to switch apps in order for me to connect to my server. When I switch back to my app the function SyncFunction.SyncUser(host, database, contact, ipaddress, pingipaddress) is not executing. The connectivity changed function is not on my App.xaml.cs it is on my Main Menu Content page because I need the sync function to be executed in my main menu not the whole app. How can I fix this?
CrossConnectivity.Current.ConnectivityChanged += async (sender, args) =>
{
var appdate = Preferences.Get("appdatetime", String.Empty, "private_prefs");
if (string.IsNullOrEmpty(appdate))
{
Preferences.Set("appdatetime", DateTime.Now.ToString(), "private_prefs");
}
else
{
if (DateTime.Now >= DateTime.Parse(Preferences.Get("appdatetime", String.Empty, "private_prefs")))
{
Preferences.Set("appdatetime", DateTime.Now.ToString(), "private_prefs");
if (CrossConnectivity.Current.IsConnected)
{
var ping = new Ping();
var reply = ping.Send(new IPAddress(pingipaddress), 5000);
if (reply.Status == IPStatus.Success)
{
lblStatus.Text = "Syncing data to server";
lblStatus.BackgroundColor = Color.FromHex("#2bcbba");
await Task.Delay(5000);
SyncFunction.SyncUser(host, database, contact, ipaddress, pingipaddress);
lblStatus.Text = "Online - Connected to server";
lblStatus.BackgroundColor = Color.FromHex("#2ecc71");
}
else
{
lblStatus.Text = "Online - Server unreachable. Connect to VPN";
lblStatus.BackgroundColor = Color.FromHex("#e67e22");
}
}
else
{
lblStatus.Text = "Offline - Connect to internet";
lblStatus.BackgroundColor = Color.FromHex("#e74c3c");
}
}
else
{
await DisplayAlert("Application Error", "It appears you change the time/date of your phone. Please restore the correct time/date", "Got it");
await Navigation.PopToRootAsync();
}
}
};
Detecting connectivity change across a VPN is not easy.
A workaround solution is to use a webservice as ping.
If you have a backend with API, this "ping" can be executed regularly to ensure the network AND the API are accessible.
This solution is to be used in addition to the connectivity check
Subscribe to connectivity changed
When conectivity looks OK, check the "ping service"
Typically in a mob app, this "ping endpoint" can be something like "/about".
Moreover, this specific service can be use to perform the compatibility version check beetween App Mob version and API version.
(look also Xamarin.Essentials to replace CrossConnectivity by Xamarin.Essentials: Connectivity, https://learn.microsoft.com/fr-fr/xamarin/essentials/connectivity?context=xamarin%2Fxamarin-forms&tabs=android)

How to manage user inputs in a short time interval?

i would like to implement a way of managing a user sending many messages in a time interval (for example 3 seconds), so that the chatbot only responds to the last one.
Example of inputs (in a gap of 3 seconds):
-Hi
-Hi
-Hi
-Help
Result: The chatbot only responds to the Help message.
Thanks in advance.
You can leverage Middleware feature to intercept every message, with which you can store every user's every message in cache, when your bot receive a new message, you can compaire with those info in cache, then dicide whether the flow needs to go forward.
Npde.js code snippet for quick test:
const moment = require('moment');
let lastMessage = null;
let lastMessageTime = null;
bot.use({
receive: (session, next) => {
let currentMessage = session
if (currentMessage.text !== lastMessage) {
lastMessage = currentMessage.text;
lastMessageTime = currentMessage.timestamp;
next();
} else {
if (moment(currentMessage.timestamp) - moment(lastMessageTime) >= 3000) {
lastMessageTime = currentMessage.timestamp;
next();
}
}
}
})
What needs you paying attention is that, in production env, you need to store the message with session/user id. E.G. Using session/user id as prefix of message and timesamp key in cache.
Please refer to https://learn.microsoft.com/en-us/bot-framework/dotnet/bot-builder-dotnet-middleware for how to intercept messages in C#,
and refer to https://learn.microsoft.com/en-us/bot-framework/nodejs/bot-builder-nodejs-intercept-messages for Node.js version.
Hope it helps.

connected users' list in sails socket

i've currently started using sailsJS with angularJs at frontend alognwith socket for realtime communiction.
Sailsjs gives built-in support to websocket through "sails.io.js".On client side after adding this library this code is added to angular's chat controller.
Client side code
io.socket.get('/chat',{token:token},function(users){
console.log(users);
});
chatController's action on sails side is like this.
Server side code
chat: function (req, res) {
console.log(req.isSocket);
//this gives true when called through client.
})
infact very new to sails so i want suggestion that how to maintain connected user's list because m not using redis as storage purpose.adapter is memory.array is not a good idea because it'll vanish when restart a server.m using sails version of 0.11.0.
thanx in advance.
I'm somewhat new but learning fast, these suggestions should get you there unless someone else responds with greatness...
They changed it in 11 but in 10.5 I use sockets.js in config folder and on connect I store the session data in an array with their socket.
I created a service in APIs/service that contains the array and socket associate function.
For v11 you can't do that exactly the same, but you can make your first 'hello' from the client call a function in a controller that calls the associate function.
A couple tips would be don't let the client just tell you who they are, as in don't just take the username from the params but get it from req.session
(This assumes you have user auth setup)
In my case I have
in api/services/Z.js (putting the file here makes it's functions globally accessible)
var socketList = [];
module.exports = {
associateSocket: function(session, socket) { // send in your username(string) socket(object) id(mongoId) and this will push to the socketlist for lookups
sails.log.debug("associate socket called!",socketList.length)
var iHateYou = socketList
//DEBUG
var sList = socketList
var util = require('util')
if (session.authenticated){
var username = session.user.auth.username
var userId = session.user.id
// sails.log.debug("Z: associating new user!",username,userId,socket)
if (username && socket && userId) {
sList[sList.length]= {
username: session.user.auth.username,
socket: socket,
userId: session.user.id,
};
sails.log.debug('push run!!! currentsocketList length',socketList.length)
} else sails.log("Z.associateSocket called with invalid data", username, userId, authId, socket)
}else{sails.log.warn("Z.associateSocket: a socket attempted to associate itself without being logged in")}
},
}
in my config/sockets.js
onConnect: function(session, socket) {
Z.associateSocket(session,socket)
if (session.user && session.user.auth){
sails.log("config/sockets.js: "+session.user.auth.username+" CONNECT! session:",session)
}else sails.log.warn('connect called on socket without an auth, the client thinks it already has a session, so we need to fix this')
// By default, do nothing.
},
Then you can make add some functions to your services file to do lookups based on username and passwords, remove sockets that are disconnecting and the like (I'm using waterlock for my auth at the moment, although debating the switch back to sails-generate-auth)
Remove your onConnect and dicconnect function from config/sockets.js.

Sailsjs Session access during custom onConnect in socket.io

I'm trying to group all my socket.io connection into groups.
I want 1 group for each sails.js session.
My first goal is authentificate all tabs in a same time.
So I tried to do this with onConnect in config/sockets.js like that :
onConnect: function(session, socket) {
// By default: do nothing
// This is a good place to subscribe a new socket to a room, inform other users that
// someone new has come online, or any other custom socket.io logic
if (typeof session.socket == 'undefined'){
session.socket = [];
}
session.socket.push(socket.id);
session.save();
console.log(session, socket);
},
// This custom onDisconnect function will be run each time a socket disconnects
onDisconnect: function(session, socket) {
// By default: do nothing
// This is a good place to broadcast a disconnect message, or any other custom socket.io logic
if(Array.isArray(session.socket)){
var i = session.socket.indexOf(socket.id);
if(i != -1) {
session.socket.splice(i, 1);
session.save();
}
}
console.log(session, socket);
},
But I realize that session doesn't save my modifications.
I tried a session.save but sailsjs doesn't know req !
Session.set(sessionKey, req.session, function (err) {
I want to access to sails.js sesion but I don't know how to do it.
I tried to search a solution but now, after 6 hours of search I think it's time to requiered some help !
Thanks and sorry for my poor english (I'm french).
There appears to be a bug in the implementation of onConnect and onDisconnect in Sails v0.9.x. You can work around it for now by adding the following line before a call to session.save in those methods:
global.req = {}; global.req.session = session;
then changing session.save() to:
session.save(function(){delete global.req;});
That will provide the missing req var as a global, and then delete the global (for safety) after the session is saved.
Note that this issue only affects sessions in the onConnect and onDisconnect methods; inside of controller code session.save should work fine.
Thanks for pointing this out!

Saving Data Locally and Remotely (Syncing)

When data is entered, it ultimately needs to be saved remotely on a server. I do want the app to work if there is no data connection at the time also, so I need to save everything locally on the phone too. The app can then sync with the server when it gets a connection.
This brings up a little issue. I'm used to saving everything on the server and then getting the records back with id's generated from the server for them. If there is no connection, the app will save locally to the phone but not the server. When syncing with the server, I don't see a way for the phone to know when a record comes back which locally record it's associated with. There isn't enough unique data to figure this out.
What is the best way to handle this?
One way I've been thinking is to change the id of the records to a GUID and let the phone set the id. This way, all records will have an id locally, and when saving to the server, it should still be a unique id.
I'd like to know what other people have been doing, and what works and what doesn't from experience.
This is how we done with a first windows phone 7 app finished few days ago with my friend.
It might not be the best solution but 'till additional refactoring it works just fine.
It's an application for a web app like a mint.com called slamarica.
If we have feature like save transaction, we first check if we have connection to internet.
// Check if application is in online or in offline mode
if (NetworkDetector.IsOnline)
{
// Save through REST API
_transactionBl.AddTransaction(_currentTransaction);
}
else
{
// Save to phone database
SaveTransactionToPhone(_currentTransaction);
}
If transaction is successfully saved via REST, it responses with transaction object and than we save it to local database. If REST save failed we save data to local database.
private void OnTransactionSaveCompleted(bool isSuccessful, string message, Transaction savedTransaction)
{
MessageBox.Show(message);
if(isSuccessful)
{
// save new transaction to local database
DatabaseBl.Save(savedTransaction);
// save to observable collection Transactions in MainViewModel
App.ViewModel.Transactions.Add(App.ViewModel.TransactionToTransactionViewModel(savedTransaction));
App.ViewModel.SortTransactionList();
// Go back to Transaction List
NavigationService.GoBack();
}
else
{
// if REST is failed save unsent transaction to Phone database
SaveTransactionToPhone(_currentTransaction);
// save to observable collection Transactions in MainViewModel
App.ViewModel.Transactions.Add(App.ViewModel.TransactionToTransactionViewModel(_currentTransaction));
App.ViewModel.SortTransactionList();
}
}
Every Transaction object has IsInSync property. It is set to false by default until we got confirmation from REST API that it's saved successful on the server.
User has ability to refresh transactions. User can click on a button Refresh to fetch new data from the server. We do the syncing in the background like this:
private void RefreshTransactions(object sender, RoutedEventArgs e)
{
if (NetworkDetector.IsOnline)
{
var notSyncTransactions = DatabaseBl.GetData<Transaction>().Where(x => x.IsInSync == false).ToList();
if(notSyncTransactions.Count > 0)
{
// we must Sync all transactions
_isAllInSync = true;
_transactionSyncCount = notSyncTransactions.Count;
_transactionBl.AddTransactionCompleted += OnSyncTransactionCompleted;
if (_progress == null)
{
_progress = new ProgressIndicator();
}
foreach (var notSyncTransaction in notSyncTransactions)
{
_transactionBl.AddTransaction(notSyncTransaction);
}
_progress.Show();
}
else
{
// just refresh transactions
DoTransactionRefresh();
}
}
else
{
MessageBox.Show(ApplicationStrings.NETWORK_OFFLINE);
}
}
private void DoTransactionRefresh()
{
if (_progress == null)
{
_progress = new ProgressIndicator();
}
// after all data is sent do full reload
App.ViewModel.LoadMore = true;
App.ViewModel.ShowButton = false;
ApplicationBl<Transaction>.GetDataLoadingCompleted += OnTransactionsRefreshCompleted;
ApplicationBl<Transaction>.GetData(0, 10);
_progress.Show();
}
OnTransactionRefreshCompleted we delete all transaction data in local database and get the latest 10 transactions. We don't need all the data, and this way user have synced data. He can always load more data by taping load more at the end of transaction list. It's something similar like those twitter apps.
private void OnTransactionsRefreshCompleted(object entities)
{
if (entities is IList<Transaction>)
{
// save transactions
var transactions = (IList<Transaction>)entities;
DatabaseBl.TruncateTable<Transaction>();
DatabaseBl.Save(transactions);
((MainViewModel) DataContext).Transactions.Clear();
//reset offset
_offset = 1;
//update list with new transactions
App.ViewModel.LoadDataForTransactions(transactions);
App.ViewModel.LoadMore = false;
App.ViewModel.ShowButton = true;
}
if (entities == null)
{
App.ViewModel.ShowButton = false;
App.ViewModel.LoadMore = false;
}
// hide progress
_progress.Hide();
// remove event handler
ApplicationBl<Transaction>.GetDataLoadingCompleted -= OnTransactionsRefreshCompleted;
}
Caveat - I haven't tried this with windows phone development but use of GUID identities is something I usually do when faced with similar situations - eg creating records when I only have a one-way connection to the database - such as via a message bus or queue.
It works fine, albeit with a minor penalty in record sizes, and can also cause less performant indexes. I suggest you just give it a shot.

Resources