I am an experienced Java programmer, but fairly new to JavaScript.
I am creating a chat library in JavaScript, and have it working, but want to know if I am going about this correctly, and following correct JavaScript coding standards.
I have a SDK
object, LiveChatConnection
class, and LiveChatListener
and Credentials
interfaces (I know classes and interfaces do not exist in JavaScript, but this seems to be how to create them).
To declare methods I am using
this.myMethod = function() {...};
I have seen other libraries put methods on the class prototype
MyClass.prototype.myMethod = function() {...}
or declare them like,
myMethod : function() {...}
Not sure which is best.
So my SDK
will be packaged in a sdk.js file on my website, then users should be able to import and use it in their web pages.
Not sure if my code makes sense from a usage perspective, or if I'm missing anything else.
var SDK = {};
function Credentials() {
this.host = "";
this.app = "";
this.url = "";
this.applicationId = "";
}
/**
* Listener interface for a LiveChatConnection.
* This gives asynchronous notification when a channel receives a message, or notice.
*/
function LiveChatListener() {
/**
* A user message was received from the channel.
*/
this.message = function(message) {};
/**
* An informational message was received from the channel.
* Such as a new user joined, private request, etc.
*/
this.info = function(message) {};
/**
* An error message was received from the channel.
* This could be an access error, or message failure.
*/
this.error = function(message) {};
/**
* Notification that the connection was closed.
*/
this.closed = function() {};
/**
* The channels users changed (user joined, left, etc.)
* This contains a comma separated values (CSV) list of the current channel users.
* It can be passed to the SDKConnection.getUsers() API to obtain the UserConfig info for the users.
*/
this.updateUsers = function(usersCSV) {};
/**
* The channels users changed (user joined, left, etc.)
* This contains a HTML list of the current channel users.
* It can be inserted into an HTML document to display the users.
*/
this.updateUsersXML = function(usersXML) {};
}
/**
* Connection class for a Live Chat, or chatroom connection.
* A live chat connection is different than an SDKConnection as it is asynchronous,
* and uses web sockets for communication.
*/
function LiveChatConnection(credentials) {
this.debug = false;
this.channel = null;
this.user = null;
this.credentials = credentials;
this.socket = null;
this.listener = null;
this.keepAlive = false;
this.keepAliveInterval = null;
/**
* Connection to the live chat server channel.
* Validate the user credentials.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
*/
this.connect = function(channel, user) {
if (this.credentials == null) {
throw "Mising credentials";
}
this.channel = channel;
this.user = user;
var host = "ws://" + this.credentials.host + this.credentials.app + "/live/chat";
if ('WebSocket' in window) {
this.socket = new WebSocket(host);
} else if ('MozWebSocket' in window) {
this.socket = new MozWebSocket(host);
} else {
this.socket = new WebSocket(host);
//throw 'Error: WebSocket is not supported by this browser.';
}
this.listener.connection = this;
var self = this;
this.socket.onopen = function () {
if (self.user == null) {
self.socket.send("connect " + self.channel.id + " " + self.credentials.applicationId);
} else {
self.socket.send(
"connect " + self.channel.id + " " + self.user.user + " " + self.user.token + " " + self.credentials.applicationId);
}
self.setKeepAlive(this.keepAlive);
};
this.socket.onclose = function () {
self.listener.message("Info: Closed");
self.listener.closed();
};
this.socket.onmessage = function (message) {
user = "";
data = message.data;
text = data;
index = text.indexOf(':');
if (index != -1) {
user = text.substring(0, index);
data = text.substring(index + 2, text.length);
}
if (user == "Online-xml") {
self.listener.updateUsersXML(data);
return;
}
if (user == "Online") {
self.listener.updateUsers(data);
return;
}
if (self.keepAlive && user == "Info" && text.contains("pong")) {
return;
}
if (user == "Info") {
self.listener.info(text);
return;
}
if (user == "Error") {
self.listener.error(text);
return;
}
self.listener.message(text);
};
};
/**
* Sent a text message to the channel.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
* Note, the listener will receive its own messages.
*/
this.sendMessage = function(message) {
this.checkSocket();
this.socket.send(message);
};
/**
* Accept a private request.
* This is also used by an operator to accept the top of the waiting queue.
* This can also be used by a user to chat with the channel bot.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
*/
this.accept = function() {
this.checkSocket();
this.socket.send("accept");
};
/**
* Test the connection.
* A pong message will be returned, this message will not be broadcast to the channel.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
*/
this.ping = function() {
this.checkSocket();
this.socket.send("ping");
};
/**
* Exit from the current private channel.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
*/
this.exit = function() {
this.checkSocket();
this.socket.send("exit");
};
/**
* Request a private chat session with a user.
* This call is asynchronous, any error or success with be sent as a separate message to the listener.
*/
this.pvt = function(user) {
this.checkSocket();
this.socket.send("pvt: " + user);
};
/**
* Disconnect from the channel.
*/
this.disconnect = function() {
this.setKeepAlive(false);
if (this.socket != null) {
this.socket.disconnect();
}
};
this.checkSocket = function() {
if (this.socket == null) {
throw "Not connected";
}
};
this.toggleKeepAlive = function() {
setKeepAlive(!this.keepAlive);
}
this.setKeepAlive = function(keepAlive) {
this.keepAlive = keepAlive;
if (!keepAlive && this.keepAliveInterval != null) {
clearInterval(this.keepAliveInterval);
} else if (keepAlive && this.keepAliveInterval == null) {
this.keepAliveInterval = setInterval(
function() {
this.ping()
},
600000);
}
}
}
SDK.chime = function() {
var sound = new Audio('chime.wav');
sound.play();
}
SDK.url = "/botlibre/rest/botlibre";
SDK.tts = function(text) {
try {
var url = SDK.url + '/form-speak?&text=';
url = url + encodeURIComponent(text);
var request = new XMLHttpRequest();
request.onreadystatechange = function() {
if (request.readyState != 4) return;
if (request.status != 200) {
console.log('Error: Speech web request failed');
return;
}
var audio = new Audio(request.responseText);
audio.mediaGroup = 'voice';
audio.play();
}
request.open('GET', url, true);
request.send();
} catch (error) {
console.log('Error: Speech web request failed');
}
}