I am making an application where users can switch between different voice rooms (sessions).
The function 'connectToSession' (see below) checks if the user is already in a session, if so will disconnect from current session and then connect to the other session and publish its stream to that session.
The switching of voice rooms works fine and to the user is all apears to be working, however every time a user switches session I get this error in the console:
Publisher State Change Failed: 'Publishing' cannot transition to 'PublishingToSession'
Publisher State Change Failed: 'Publishing' cannot transition to 'Publishing'
From my debugging it seems to have occurred on the line where session.publish is called
var session = null;
var publisher = null;
var subscribers = {};
function connectToSession(sessionId, token) {
if (session) {
session.disconnect();
}
if (!publisher) {
//First time so we need to initialise publisher
var pubOptions = {
videoSource: null,
name: user_id
};
publisher = OT.initPublisher(null, pubOptions, function() {
//Publisher initialised
});
publisher.on({
'streamDestroyed': function(event) {
event.preventDefault();
}
});
}
session = OT.initSession(apiKey, sessionId);
session.on({
'streamCreated': function(event) {
// Subscribe to others stream
subscribers[event.stream.name] = session.subscribe(event.stream);
},
'sessionConnected': function(sessionConnectEvent) {
// Session Connected
},
'streamDestroyed': function(event) {
//Stream removed from session
delete subscribers[event.stream.name];
}
});
session.connect(token,
function(error) {
if (error) {
console.error(error);
}
else {
session.publish(publisher, function() {
//Finished publishing
}
);
}
});
}
Any ideas what is causing this error?
if (session) {
if (publisher) {
session.unpublish(publisher);
}
session.disconnect();
}
A workaround is to explicitly call unpublish for a publisher before disconnecting from the session.
Related
I developed the chat room app with node.js & expressjs in backend. Use socket.io with chat rooms.
And I found the when I send the message, outgoing messages are not shown. But it works well before so I research the github history but the codes are same as before.
And one thing I cannot understand is, ingoing messages functions are works well, only outgoing messages are not working.
But the DB part works well so When I refresh the page all the chat's are shown well.
The code shown below is part of my app.js's socketIO part.
[app.js]
const io = require('socket.io')(socket);
/* Socket IO Functions */
io.on('connection', function (socket) {
// Join Room Scoket
socket.on('JoinRoom', function (data) {
socket.leave(`${data.leave}`)
// console.log(`Leave ROOM : ${data.leave}`)
socket.join(`${data.joinedRoomName}`);
// console.log(`NEW JOIN IN ${data.joinedRoomName}`)
// console.log(`RECEIVER : ${data.receiver}`)
// When Reads the message SET notice to '1'
// db.query(`UPDATE chatData SET notice='1' WHERE chatReceiver=? AND roomName=?`, [data.receiver, data.joinedRoomName])
// console.log(data);
Chat.aggregate([{
$match: {
'chatReceiver': data.receiver,
'roomName': data.joinedRoomName,
'chatNotice': 1
}
},
{
$set: {
'chatNotice': 0
}
}
], (err, result) => {
if (err) throw err;
// console.log(result);
})
})
// Send Message Socket
socket.on('say', function (data) {
//chat message to the others
socket.to(`${data.joinedRoomName}`).emit('mySaying', data);
console.log(data)
console.log(`Message Send to : ${data.joinedRoomName}`)
console.log(`Message Content : ${data.userId} : ${data.msg}`);
// Chat Message Save to DB SQL
Chat.create({
'roomName': data.joinedRoomName,
'chatSender': data.userId,
'chatReceiver': data.receiver,
'chatMessage': data.msg
})
});
}
[chat.js [Client Side]]
let socket = io();
/* SocketIO Functions */
$(function () {
$('#message').focus(); // Init Focus to Input
let fontColor = 'black';
let nickName = '';
let whoIsTyping = [];
/* Submit Event (Keyboard Enter) */
$('#chat').submit(function () {
if (joinedRoomName === undefined) {
/* Not yet joined Alert */
const Toast = Swal.mixin({
toast: true,
position: 'bottom',
showConfirmButton: false,
timer: 5000,
timerProgressBar: true,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer)
toast.addEventListener('mouseleave', Swal.resumeTimer)
}
})
Toast.fire({
icon: 'warning',
title: 'Please joined room first!'
})
$('#message').val('Joined ROOM First!!');
} else {
if ($('#message') !== '') {
let msg = $('#message').val();
socket.emit('say', {
msg: msg,
userId: userId,
loginedId: userId,
receiver: others,
joinedRoomName: joinedRoomName
});
}
// Say event means someone transmitted chat
$('#message').val('');
socket.emit('quitTyping')
}
return false;
});
/* Click Event (Click Send Button) */
$('.msg_send_btn').click(function () {
if (joinedRoomName === undefined) {
$('#message').val('Joined ROOM First!!');
} else {
//submit only if it's not empty
if ($('#message').val() != "") {
let msg = $('#message').val();
socket.emit('say', {
msg: msg,
userId: userId,
loginedId: userId,
receiver: others,
joinedRoomName: joinedRoomName
});
}
// Say event means someone transmitted chat
$('#message').val('');
socket.emit('quitTyping')
}
return false;
});
/* Sending Messages Socket */ THIS PART IS CHAT PART!!!!
socket.on('mySaying', function (data) {
d = Date.now();
d = new Date(d);
d = `${d.getFullYear()}-${d.getMonth() + 1}-${d.getDate()} ${d.getHours() > 12 ? d.getHours() - 12 : d.getHours()} : ${d.getMinutes()} ${(d.getHours() >= 12 ? "PM" : "AM")}`;
console.log(data.userId);
console.log(userId);
if (data.userId == userId) {
$('.msg_history').append(`<div class="outgoing_msg"><div class="sent_msg"><p>${data.msg}</p><span class="time_date"> ${d}</span></div></div>`);
} else {
$('.msg_history').append(`<div class="incoming_msg"><div class="incoming_msg_img"><img src="${avatar_url}" alt="sunil"></div><div class="received_msg"><div class="received_withd_msg"><p>${data.msg}</p><span class="time_date">${d}</span></div></div></div>`);
$('#chatData').text(`${data.msg}`)
}
Scroll();
});
/* Typing... Socket */
socket.on('typing', function (whoIsTyping) {
whoIsTyping = others;
$('#message').attr('placeholder', `${whoIsTyping} is typing..`) // Typing... Message
});
/* End Typing Socket */
socket.on('endTyping', function () {
whoIsTyping = [];
$('#message').attr('placeholder', "Type a Message"); // If Notyping Reset to Init placeholder
})
/* Input Typing Socket */
$('#message').keyup(function (event) {
if ($('#message').val() != "" && !whoIsTyping.includes(others)) {
socket.emit('typing', {
others,
joinedRoomName
});
} else if ($('#message').val() == "" && whoIsTyping.includes(others)) {
socket.emit('quitTyping', {
others,
joinedRoomName
});
}
});
});
It looks like this. When I send chat to someone it send to other person works well but in my page, the chat that I sent is not shown.
I don't know where this bug come from.
In your app.js, you are using
socket.to("ROOM").emit('EVENT', data);
Which is, sending to all clients in "ROOM" room except sender
thus the sender will not receive the event (which is happening in your case).
You want to include the sender in a broadcast event use following
io.in("ROOM").emit("EVENT", data);
and for your specific case
io.in(`${data.joinedRoomName}`).emit('mySaying', data);
look at Emit cheatsheet
First, thanks to answer above. And the codes are right.
In my client side socketio version is 2.X but the server side socketio is updated to 3.X so it's not wokring.
If I use version 2.X use my code, but use 3.0
io.in(`${data.joinedRoomName}`).emit('mySaying', data);
is the answer.
I'm trying to implement silent login in oidc-client to use with Angular 2
How can use oidc client to silently check if user is already logged in (idsvr4) and display the login details.
the following code works, but i need to refresh the page
idsvr 4 client
// JavaScript Client
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
RedirectUris = { "http://localhost:5002/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5002/index.html" },
AllowedCorsOrigins = { "http://localhost:5002" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1",
},
RequireConsent=false,
AllowOfflineAccess = true
}
client side code
var config = {
authority: "http://localhost:5000",
client_id: "js",
redirect_uri: "http://localhost:5002/callback.html",
silent_redirect_uri: "http://localhost:5002/callback.html",
response_type: "id_token token",
scope: "openid profile api1 offline_access",
post_logout_redirect_uri: "http://localhost:5002/index.html",
// Number of seconds before the token expires to trigger
// the `tokenExpiring` event
accessTokenExpiringNotificationTime: 4,
// Do we want to renew the access token automatically when it's
// about to expire?
automaticSilentRenew: false,
// Do we want to filter OIDC protocal-specific claims from the response?
filterProtocolClaims: false,
// use localStorage
userStore: new Oidc.WebStorageStateStore({ store: window.localStorage })
};
var mgr = new Oidc.UserManager(config);
// You can hook a logger to the library.
// Conveniently, the methods exposed by the logger match
// the `console` object
Oidc.Log.logger = console;
// When a user logs in successfully or a token is renewed, the `userLoaded`
// event is fired. the `addUserLoaded` method allows to register a callback to
// that event
mgr.events.addUserLoaded(function (loadedUser) {
console.log("$$$$$$$$$$$$$$$$$$$$$$$ added");
});
// Same mechanism for when the automatic renewal of a token fails
mgr.events.addSilentRenewError(function (error) {
console.error('$$$$$$$$$$$$$$$$$$$$$$$ error while renewing the access token', error);
});
// When the automatic session management feature detects a change in
// the user session state, the `userSignedOut` event is fired.
mgr.events.addUserSignedOut(function () {
alert('The user has signed out');
});
mgr.getUser().then(function (user) {
if (user) {
log("User logged in", user.profile);
}
else {
log("User not logged in");
// log("*****************************************************");
mgr.signinSilent()
.then(function (newUser) {
console.log("doneeeeeeeeeeeeeeeeeeeee");
console.log(newUser);
console.log(newUser.profile);
}).catch(function (e) {
console.log("======== " + e);
});;
mgr.signinSilentCallback().then(function (newUser) {
console.log("doneeeeeeeeeeeeeeeeeeeee");
console.log(newUser);
console.log(newUser.profile);
}).catch(function (e) {
console.log("&&&&&&&&&&&& "+e);
});
}
});
no user is getting returned in either methods of silentSignIn
I want to get if user is logged in and retrieve the information as soon as the client is open.
Or if there's a better way to do this in angular 2 then it's better.
I had the same problem. I managed to solve it by using the following signin() method and by managing the process sign in response:
function signin() {
manager.createSigninRequest().then(function (req) {
window.location = req.url;
}).catch(function (err) {
log(err);
});
}
manager.processSigninResponse().then(function (response) {
log("signin response success", response);
}).catch(function (err) {
});
manager.events.addUserLoaded(function (user) {
manager.getUser().then(function () {
log("User logged in", user.profile);
});
});
function api() {
mgr.getUser().then(function (user) {
var url = "http://localhost:5001/identity";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function () {
log(xhr.status, JSON.parse(xhr.responseText));
}
xhr.setRequestHeader("Authorization", "Bearer " + idToken);
xhr.send();
});
}
I created logins and unique todo lists per user using Firebase and TodoMVC as proof of concept for another project. I'm using Firebase and Google to log users in and when things are working, they get a unique persistent todo list.
Everything works (I think) when the user is already logged into Google via their browser.
The problem happens when they aren't. Instead of their todo list, or a blank one under their user id, they see the todo list of an undefined user until they hit refresh, then things work again. The Firebase url doesn't see their uid until they hit refresh. If you're logged in to Google, you can replicate the error by opening an incognito window.
You can see the errors in my code at http://lacyjpr.github.io/todo-backbone, and my repo at https://github.com/lacyjpr/todo-backbone
This is my authentication code:
// Authenticate with Google
var ref = new Firebase(<firebase url>);
ref.onAuth(function(authData) {
if (authData) {
console.log("Authenticated successfully");
} else {
// Try to authenticate with Google via OAuth redirection
ref.authWithOAuthRedirect("google", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
}
});
}
})
// Create a callback which logs the current auth state
function authDataCallback(authData) {
if (authData) {
console.log("User " + authData.uid + " is logged in with " + authData.provider);
uid = authData.uid;
} else {
console.log("User is logged out");
}
}
This is the code that gets the UID to use as a firebase key:
// Get the uid of the user so we can save data on a per user basis
var ref = new Firebase(<firebase url>);
var authData = ref.getAuth();
if (authData) {
var uid = authData.uid;
console.log(uid);
}
// The collection of todos is backed by firebase instead of localstorage
var TodoList = Backbone.Firebase.Collection.extend({
// Reference to this collection's model.
model: app.Todo,
// Save all of the todos to firebase
url: <firebase url> + uid,
Thanks in advance for any advice you can offer!
You're calling .getAuth() before a user is authenticated.
Your app heavily relies on the uid to work properly. So in your case you would want to kick off the Backbone portion of the app once user has successfully authenticated.
You could modify your app.js to only kick off if the user is authenticated.
// js/app.js
var app = app || {};
var ENTER_KEY = 13;
$(function() {
var ref = new Firebase(<firebase url>);
var authData = ref.getAuth();
if (authData) {
ref.authWithOAuthRedirect("google", function(error, authData) {
if (error) {
console.log("Login Failed!", error);
} else {
// kick off app
new app.AppView();
}
});
} else {
new app.AppView();
}
});
While this will work, it isn't the ideal solution. But there is no other option since you don't have a login screen.
Ideally, you'd want to provide the user a place to login, and then you'd have access the .getAuth() value.
Also, don't worry about storing the uid on the window. .getAuth() is the cached user, so there's no network call to get the data.
I am following a guide on how to implement the chrome push notification and I am trying to implement it in a Meteor app as a package.
Because I am unable to include the manifest.json I am getting "Registration failed - no sender id provided" or "Registration failed - permission denied". So how can I include this file in my project?
The manifest.json looks like this:
{
"permissions": [ "gcm" ],
"name": "push",
"short_name": "push notification",
"display": "standalone",
"gcm_sender_id": "0000000000000"
}
I have tried including it with the package.js like:
api.addAssets('manifest.json', 'client');
And also put the required variables (gcm_sender_id) in settings.json and starting meteor with meteor --settings settings.json but nothing works.
My service worker registration starts with calling Cpn.serviceWorkerRegistration:
Cpn = {};
Cpn.serviceWorkerRegistration = function () {
console.log("serviceWorkerRegistration called");
subscribe();
console.log(navigator);
// Check that service workers are supported, if so, progressively
// enhance and add push messaging support, otherwise continue without it.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(initialiseState);
} else {
console.warn('Service workers aren\'t supported in this browser.');
}
}
// Once the service worker is registered set the initial state
initialiseState = function () {
console.log("initialiseState");
// Are Notifications supported in the service worker?
if (!('showNotification' in ServiceWorkerRegistration.prototype)) {
console.warn('Notifications aren\'t supported.');
return;
}
// Check the current Notification permission.
// If its denied, it's a permanent block until the
// user changes the permission
if (Notification.permission === 'denied') {
console.warn('The user has blocked notifications.');
return;
}
// Check if push messaging is supported
if (!('PushManager' in window)) {
console.warn('Push messaging isn\'t supported.');
return;
}
// We need the service worker registration to check for a subscription
navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
// Do we already have a push message subscription?
serviceWorkerRegistration.pushManager.getSubscription()
.then(function (subscription) {
if (!subscription) {
return;
}
// Keep your server in sync with the latest subscriptionId
sendSubscriptionToServer(subscription);
})
.catch(function (err) {
console.warn('Error during getSubscription()', err);
});
});
}
function subscribe() {
navigator.serviceWorker.ready.then(function (serviceWorkerRegistration) {
serviceWorkerRegistration.pushManager.subscribe()
.then(function (subscription) {
// The subscription was successful
// TODO: Send the subscription.endpoint to your server
// and save it to send a push message at a later date
return sendSubscriptionToServer(subscription);
})
.catch(function (e) {
if (Notification.permission === 'denied') {
// The user denied the notification permission which
// means we failed to subscribe and the user will need
// to manually change the notification permission to
// subscribe to push messages
console.warn('Permission for Notifications was denied');
} else {
// A problem occurred with the subscription; common reasons
// include network errors, and lacking gcm_sender_id and/or
// gcm_user_visible_only in the manifest.
console.error('Unable to subscribe to push.', e);
}
});
});
}
And the service worker looks like this:
self.addEventListener('push', showNotification)
self.addEventListener('notificationclick', closeNotificationAndOpenWindow)
function showNotification(event) {
console.log('Received a push message', event)
var title = 'Yay a message.'
var body = 'We have received a push message.'
var icon = '/images/icon-192x192.png'
var tag = 'simple-push-demo-notification-tag'
event.waitUntil(
self.registration.showNotification(title, {
body: body,
icon: icon,
tag: tag
})
)
}
function closeNotificationAndOpenWindow(event) {
console.log('On notification click: ', event.notification.tag)
// Android doesn’t close the notification when you click on it
// See: http://crbug.com/463146
event.notification.close()
// This looks to see if the current is already open and
// focuses if it is
event.waitUntil(clients.matchAll({
type: "window"
}).then(function (clientList) {
for (var i = 0; i < clientList.length; i++) {
var client = clientList[i]
if (client.url == '/' && 'focus' in client)
return client.focus()
}
if (clients.openWindow)
return clients.openWindow('/')
}))
}
First a little background:
I am working on an seperate mobile application that is connected with the main app. The connection is succesfully initiated and I can retrieve all collections, through subscriptions:
Remote = DDP.connect('http://localhost:3000/');
Meteor.users = new Meteor.Collection('users', {
connection: Remote
});
Remote.subscribe('users', true);
Now I want to make sure users can log in through the interface of the second app. After installing the accounts-password and the meteor-ddp-login package, I should be able to authenticate with the main app by using the next piece of code in the client side.
var Remote = DDP.connect('http://localhost:3000/');
DDP.loginWithPassword(Remote, {
username: username
}, password, function(error) {
if (!error) {
console.log(username + " is logged in!");
} else {
console.log(error);
}
});
Well, so far so good. No errors appear and the console logs a success message. Now the question comes:
How can I retrieve the user object of the user who just logged in.
I've set up several publish functions in the main app, but the user data does not become available to the client in the second app (other collections work fine, but Meteor.user() is undefined).
And also: How can I authenticate users who login with Facebook/Google/Twitter
Came across this, I had a similar need recently. Following code works in Meteor version 1.2.0.2
if (Meteor.isClient) {
Meteor.startup(function(){
//Seems that without this, on page refresh, it doesn't work.
//COMMENT: Ideally this should not be needed if the core takes care of this use case of a different connection for Accounts
//hack block 1***********
var token = Accounts._storedLoginToken();
if(token) {
Meteor.loginWithToken(token, function(err){
// this is going to throw error if we logged out
if(err)
console.log(err);
else
console.log('loginWithToken');
});//loginWithToken
}
//hack block 1***********
});//startup function
var connection = DDP.connect("http://localhost:3060");
Accounts.connection= connection;
//COMMENT: Ideally this should not be needed if the core takes care of this use case of a different connection for Accounts
//hack block 2***********
Accounts.users = new Meteor.Collection('users', {
connection: connection
});
//hack block 2***********
Tracker.autorun(function () {
//No code which directly affects the functionality. Just for testing
console.log(Meteor.user());
Accounts.connection.call('user',function(err,result){
if(err)
console.log(err);
if(result){
console.log(result);
if(result._id === Meteor.user()._id){
console.log("Server and client shows that the same user has logged in");
} else {console.log("Server and client shows different users");}
}
})
});
Template.register.events({
'submit #register-form' : function(e, t) {
e.preventDefault();
var email = t.find('#account-email').value
, password = t.find('#account-password').value;
Accounts.createUser({email:email,password:password}, function(err,result){
if (err) {
// Inform the user that account creation failed
console.log(err);
} else {
// Success. Account has been created and the user
// has logged in successfully.
console.log("registered user");
console.log('response is '+ result);
console.log(Meteor.user());
}
});//createUser
return false;
}
});//register
Template.login.events({
'submit #login-form': function(e,t){
e.preventDefault();
var email = t.find('#login-email').value
, password = t.find('#login-password').value;
Meteor.loginWithPassword(email, password, function(err){
if (err)
console.log(err);
else
// The user has been logged in.
console.log('logged in successfully');
});
return false;
}
});//login
Template.statusloggedin.events({
'click #logout': function(e,t){
e.preventDefault();
Meteor.logout();
return false;
}
});//logout
}