Unable to join chat channel - twilio

When trying to join a channel in the twilio code I've been working with, it comes up with the error saying that it "Cannot read property 'getChannelByUniqueName' of null". The chat works but when I try to open it up on a different browser, like firefox instead of chrome, it says the error "Channel with provided unique name already exist". Can anyone help with this problem?
// Initialize the Chat client
chatClient = new Twilio.Chat.Client(data.token);
joinChannels(chatClient);
});
function joinChannels(chatClient) {
chatClient.getSubscribedChannels();
joinChannel('generalss','Generals Chat Channel');
}
function joinChannel(channelName, channelFriendlyName) {
console.log(channelName);
console.log(chatClient);
print('Attempting to join "' + channelName + '" chat channel...');
var promise = chatClient.getChannelByUniqueName(channelName);
promise.then(function(channel) {
console.log('Found ' + channelName + ' channel:');
channels[channelName] = channel;
console.log(channels);
setupChannel();
}).catch(function() {
// If it doesn't exist, let's create it
chatClient.createChannel({
uniqueName: channelName,
friendlyName: channelFriendlyName
}).then(function(channel) {
channels[channelName] = channel;
setupChannel(channelName);
});
});
}

Twilio developer evangelist here.
It looks to me like you aren't passing the chatClient to your joinChannel method (and secondly that the client might not be fully initialised yet).
I would initialise the client with the following, which uses the create method that returns a promise that resolves when the Client is ready.
// Initialize the Chat client
new Twilio.Chat.Client.create(data.token).then(function(chatClient) {
joinChannels(chatClient);
});
});
Then, make sure you pass the client through to the joinChannel method:
function joinChannels(chatClient) {
chatClient.getSubscribedChannels();
joinChannel(chatClient, 'generalss','Generals Chat Channel');
}
function joinChannel(chatClient, channelName, channelFriendlyName) {
// the rest...
}
Let me know if that helps at all.

Related

Twilio channel already exists

How can I fix this porblem:
Channel with provided unique name already exists
Here is the code for creating channel:
tc.joinGeneralChannel = function () {
console.log('Attempting to join ' + $channelName + 'chat channel...');
if (!tc.generalChannel) {
console.log('Channel doesn\'t exists');
// If it doesn't exist, let's create it
tc.messagingClient.createChannel({
uniqueName: $channelName,
friendlyName: $channelName
}).then(function (channel) {
tc.generalChannel = channel;
tc.loadChannelList(tc.joinGeneralChannel);
});
} else {
setupChannel(tc.generalChannel);
}
};
The behavior is weird because the issue is not consistent.
Most of my code are the same with the tutorial twilio provided for laravel framework Twilio Docs
Is there a way to check if the unique name is already exists and then just join in there?

Twilio Video - switch media devices option not working

I am using twilio with twilio-video v beta-2 counting on the master branch of this repohttps://github.com/twilio/video-quickstart-js
I got to display the select media and push the devices into it but when I am trying to updateVideoDevice I got an error
updateVideoDevice error TypeError: track must be a LocalAudioTrack, LocalVideoTrack, LocalDataTrack, or MediaStreamTrack
at Object.INVALID_TYPE (index.js:30952)
at Object.validateLocalTrack (index.js:31469)
at LocalParticipant.unpublishTrack (index.js:17047)
at index.js:17096
at Array.reduce (<anonymous>)
at LocalParticipant.unpublishTracks (index.js:17095)
at index.js:36056
my updateVideoDevice function is as the following
function updateVideoDevice(event) {
const select = event.target;
const localParticipant = room.localParticipant;
if (select.value !== '') {
Video.createLocalVideoTrack({
deviceId: { exact: select.value }
}).then(function(localVideoTrack) {
const tracks = Array.from(localParticipant.videoTracks.values());
localParticipant.unpublishTracks(tracks);
log(localParticipant.identity + " removed track: " + tracks[0].kind);
detachTracks(tracks);
localParticipant.publishTrack(localVideoTrack);
log(localParticipant.identity + " added track: " + localVideoTrack.kind);
const previewContainer = document.getElementById('local-media');
attachTracks([localVideoTrack], previewContainer);
})
.catch(error => {
console.error('updateVideoDevice error' ,error);
});
}
}
can any one explain what I am doing wrong?
Twilio developer evangelist here.
This looks to be a breaking change between Twilio Video JS v1 and v2. In the v2 documentation, calling localParticipant.videoTracks returns a Map of <Track.SID, LocalVideoTrackPublication>. Calling .values() on that map returns an iterator of LocalVideoTrackPublications which is then turned to an array using Array.from.
The issue is that you then pass that array of LocalVideoTrackPublications to localParticipant.unpublishTracks(tracks); which causes the error because unpublishTracks expects an array of LocalTracks not LocalVideoTrackPublications.
You could fix this by mapping over the publications and returning the track property:
const tracks = Array.from(localParticipant.videoTracks.values())
.map(publication => publication.track);
Let me know if that helps.

putting an outgoing call from a twilio client to a phone on hold(Get phone side call Sid)

I am trying to implement 'hold call' functionality into my system. I have looked at this question and some twilio docs, and recommended way to do this is to dequeue the call, which will automatically play the hold music, and then retrieve from queue when hold is complete(un-hold).
This works perfectly fine, when I have an incoming call from a mobile, to my twilio client, and I can dequeue the call, and all works fine.
However when I do it with the outgoing call from the twilio client to the mobile, if I update the call to issue dequeue instruction, I get to hear the hold music on the client side itself, and the phone gets disconnected. I suppose this is because I have set the client leg of the call on hold. So the question is how do I get the call sid for the mobile leg of the call.
I have tried querying CallResource by ParentCallId, but that does not return anything in the case of outgoing calls. Any ideas?
Call is initiated on the client with:
var params = {
To: num
};
console.log('Calling ' + num + '...');
Twilio.Device.connect(params);
The connect API callback uses a simple Dial verb.
Client code for saving callid on connect:
Twilio.Device.connect(function (conn) {
if (conn._direction === 'OUTGOING') {
$scope.outgoing_call_sid = conn.parameters.CallSid;
$scope.number = conn.message.To;
} else {
$scope.incoming_call_sid = conn.parameters.CallSid;
$scope.number = conn.parameters.From;
}
$scope.message = 'In call with ' + $scope.number;
$scope.status = 'InCall';
});
Client code on hold button click:
$scope.hold = function () {
$scope.status = 'Hold';
$scope.message = 'Putting on hold...';
if ($scope.outgoing_call_sid) {
return $http.get(serviceBase + 'api/twilio/hold?callid=' + $scope.outgoing_call_sid);
}
};
Server side Hold API call:
public IHttpActionResult Hold(string callid) { /
//callid = GetLegCallId(callid); //Try to replace with child call
CallResource.Update(new UpdateCallOptions(callid) { Url = ConfigurationManager.AppSettings["ngrokUrl"] + "/api/twilio/enqueue", Method = HttpMethod.Get });
return Ok();
}
Code for getting any child calls:
public string GetLegCallId(string callId)
{
var calls = CallResource.Read(new ReadCallOptions() { ParentCallSid = callId });
if (calls.GetEnumerator().Current != null)
return calls.GetEnumerator().Current.Sid;
}
My bad. Twilio wasnt the issue. Issue was with usage of calls.GetEnumerator().Current != null.
Should do MoveNext on the Enumerator, before Current will have a value. Resolved by doing that. Stupid:(

Send notification from web to android device using Firebase

I am trying for a while now to implement this flow: When user adds some files on server app, notification should trigger and send from server to FCM and that from there to pass message saying something like: 'New file has been added'.
Basically I want to inform mobile device user that something on server has been changed.
I have tried many things, but nothing seems to work as I would expect, at least.
On the mobile side I have set up Firebase inside my Xamarin.Android project, and when I am sending notifications directly from Firebase console, I get notifications, and everything is good.
But I don't want to send notifications via Firebase console, I would rather send notification from server (which is ASP.NET MVC project) to Firebase console and then pass it from there to android device.
My first question would be: Has anybody got an idea how can I inform web app about device_id? Is there some way that android device send this information on server? And maybe from there I can store that data and update it occasionally, since it is basically a refresh token.
My second problem is this: Even when I hard code current device_id of an active android device and try to send a message from server whit this code:
public class FirebaseService : IFirebaseService
{
public void SendMessageToClientApplication(string message, string serverApiKey, string senderId, string deviceId)
{
AndroidFCMPushNotificationStatus result = new AndroidFCMPushNotificationStatus();
try
{
result.Successful = false;
result.Error = null;
deviceId = "eMk6mD8P8Dc:APA91bG5Lmqn4Hwb4RZJ1Mkdl8Rf_uYQsQCEfDJK334tzSvIGzdao7o2X6VmtcTEp_Li0mG8iUoUT7-_RnZxQKocHosZwx6ITWdpmQyCwUv60IIIy0vxNlEaccT6RqK6c-cE1C6I3FTT";
var value = message;
WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
tRequest.Method = "post";
tRequest.ContentType = "application/x-www-form-urlencoded;charset=UTF-8";
tRequest.Headers.Add(string.Format("Authorization: key={0}", serverApiKey));
tRequest.Headers.Add(string.Format("Sender: id={0}", senderId));
string postData = "collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.message="
+ value + "&data.time=" + DateTime.Now.ToString() + "&registration_id=" + deviceId + "";
Byte[] byteArray = Encoding.UTF8.GetBytes(postData);
tRequest.ContentLength = byteArray.Length;
using (Stream dataStream = tRequest.GetRequestStream())
{
dataStream.Write(byteArray, 0, byteArray.Length);
using (WebResponse tResponse = tRequest.GetResponse())
{
using (Stream dataStreamResponse = tResponse.GetResponseStream())
{
using (StreamReader tReader = new StreamReader(dataStreamResponse))
{
String sResponseFromServer = tReader.ReadToEnd();
result.Response = sResponseFromServer;
}
}
}
}
}
catch (Exception ex)
{
result.Successful = false;
result.Response = null;
result.Error = ex;
}
}
}
I get nothing both in Firebase console and of course nothing on device as well.
I have tried to implement Firebase web as javascript on my server app like this:
<script>
var config = {
apiKey: "mykey",
authDomain: "myauthdomain",
databaseURL: "mydatabaseurl",
projectId: "myprojectid",
storageBucket: "mystoragebucket",
messagingSenderId: "mysenderid"
};
window.onload = function () {
firebase.initializeApp(config);
const messaging = firebase.messaging();
messaging.requestPermission()
.then(function () {
console.log('Notification permission granted.');
return messaging.getToken()
})
.then(function (token) {
console.log(token);
})
.catch(function (err) {
console.log('Unable to get permission to notify.', err);
});
messaging.onMessage(function (payload) {
console.log('onMessage: ', payload);
});
}
</script>
But this code gets some kind of a different device_id(aka token), probably one generated for that server machine.
Does anybody has experience with sending device_id to server app and from there sending notification message to Firebase console? I would appreciate some code examples, tutorials or anything that can help, since I was unable to find something useful during my google search.
My first question would be: Has anybody got an idea how can I inform web app about device_id?
The most common approach is to store the list of device tokens (each device that uses FCM has such a token) in a database, such as the Firebase Database. There is an example of this in the Cloud Functions for Firebase documentation. In this example the devices receiving the messages are web pages, but the approach is the same for iOS and Android.
I also recommend reading Sending notifications between Android devices with Firebase Database and Cloud Messaging. In this article, instead of sending to a device token, each user subscribes to a topic. That prevents having to manage the device tokens in your code.

two way communication between extension and content javascript files

i am trying to accomplish a two way communication request response in my firefox sidebar extension, i have a file named event.js this resides on the content side, i have another file called sidebar.js file which is residing in the xul. I am able to communicate from event.js to sidebar.js file using the dispatchEvent method. my event in turn raises a XMLHttpRequest in sidebar.js file which hits the server and sends back the response. Now, here i am unable to pass the response to the event.js file. I want the response to be accessed in the event.js file. Till now i have achieved only one way communication. Please help me in getting the two way communication.
Code is as follows:
// event.js file
// This event occurs on blur of the text box where i need to save the text into the server
function saveEvent() {
var element = document.getElementById("fetchData");
element.setAttribute("urlPath", "http://localhost:8080/event?Id=12");
element.setAttribute("jsonObj", convertToList);
element.setAttribute("methodType", "POST");
document.documentElement.appendChild(element);
var evt = document.createEvent("Events");
evt.initEvent("saveEvent", true, true);
element.dispatchEvent(evt);
//Fetching the response over here by adding the listener
document.addEventListener("dispatchedResponse", function (e) { MyExtension.responseListener(e); }, false, true);
}
var MyExtension = {
responseListener: function (evt) {
receivedResponse(evt.target.getAttribute("responseObject"));
}
}
function receivedResponse(event) {
alert('response: ' + event);
}
// sidebar.js file
window.addEventListener("load", function (event) {
var saveAjaxRequest = function (urlPath, jsonObj, methodType, evtTarget) {
var url = urlPath;
var request = Components.classes["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Components.interfaces.nsIXMLHttpRequest);
request.onload = function (aEvent) {
window.alert("Response Text: " + aEvent.target.responseText);
saveResponse = aEvent.target.responseText;
//here i am again trying to dispatch the response i got from the server back to the origin, but unable to pass it...
evtTarget.setAttribute("responseObject", saveResponse);
document.documentElement.appendChild(evtTarget);
var evt = document.createEvent("dispatchedRes"); // Error line "Operation is not supported" code: "9"
evt.initEvent("dispatchedResponse", true, false);
evtTarget.dispatchEvent(evt);
};
request.onerror = function (aEvent) {
window.alert("Error Status: " + aEvent.target.status);
};
//window.alert(methodType + " " + url);
request.open(methodType, url, true);
request.send(jsonObj);
};
this.onLoad = function () {
document.addEventListener("saveEvent", function (e) { MyExtension.saveListener(e); }, false, true);
}
var MyExtension =
{
saveListener: function (evt) {
saveAjaxRequest(evt.target.getAttribute("urlPath"), evt.target.getAttribute("jsonObj"), evt.target.getAttribute("methodType"), evt.originalTarget);
}
};
});
Why are you moving your fetchData element into the sidebar document? You should leave it where it is, otherwise your content code won't be able to receive the event. Also, use the content document to create the event. Finally, document.createEvent() parameter for custom events should be "Events". So the code after your //here i am again trying comment should look like:
evtTarget.setAttribute("responseObject", saveResponse);
var evt = evtTarget.ownerDocument.createEvent("Events");
evt.initEvent("dispatchedResponse", true, false);
evtTarget.dispatchEvent(evt);
Please note however that your code as you show it here is a huge security vulnerability - it allows any website to make any HTTP requests and get the result back, so it essentially disables same-origin policy. At the very least you need to check that the website talking to you is allowed to do it (e.g. it belongs to your server). But even then it stays a security risk because server response could be altered (e.g. by an attacker on a public WLAN) or your server could be hacked - and you would be giving an attacker access to sensitive data (for example he could trigger a request to mail.google.com and if the victim happens to be logged in he will be able to read all email data). So please make this less generic, only allow requests to some websites.

Resources