/**
* @namespace FlashphonerSFUExtended
*/
const {v4: uuidv4} = require("uuid");
const ws = require("./ws");
const roomApi = require("./room");
const promises = require("./promise");
const constants = require("./constants");
const logger = require("./logger");
const SFU_STATE = constants.SFU_STATE;
const SFU_EVENT = constants.SFU_EVENT;
const SFU_INTERNAL = constants.SFU_INTERNAL_API;
const sfu = {};
let rooms = {};
let connection = ws.createConnection();
let server;
const callbacks = {};
let state = SFU_STATE.NEW;
let connectionConfig;
let user;
function setupConnection(connection) {
connection.onMessage = function(name, msg){
switch (name) {
case SFU_INTERNAL.DEFAULT_METHOD:
//filter messages
if (msg[0].type === SFU_INTERNAL.MESSAGE) {
notify(SFU_EVENT.MESSAGE, msg[0].message);
} else if (msg[0].type === SFU_INTERNAL.MESSAGE_STATE) {
if (!promises.resolve(msg[0].internalMessageId, msg[0].status)) {
notify(SFU_EVENT.MESSAGE_STATE, msg[0].status);
}
} else if (msg[0].type === SFU_INTERNAL.USER_LIST) {
promises.resolve(msg[0].internalMessageId, msg[0].list);
notify(SFU_EVENT.USER_LIST, msg[0].list);
} else if (msg[0].type === SFU_INTERNAL.USER_CALENDAR) {
promises.resolve(msg[0].internalMessageId, msg[0].calendar);
notify(SFU_EVENT.USER_CALENDAR, msg[0].calendar);
} else if (msg[0].type === SFU_INTERNAL.NEW_CHAT) {
if(!promises.resolve(msg[0].internalMessageId, msg[0].info)) {
notify(SFU_EVENT.NEW_CHAT, msg[0].info);
}
} else if (msg[0].type === SFU_INTERNAL.CONTACT_INVITE) {
if(!promises.resolve(msg[0].internalMessageId, msg[0].invite)) {
notify(SFU_EVENT.CONTACT_INVITE, msg[0].invite);
}
} else if (msg[0].type === SFU_INTERNAL.CONTACT_UPDATED) {
if(!promises.resolve(msg[0].internalMessageId, msg[0].contact)) {
notify(SFU_EVENT.CONTACT_UPDATE, msg[0].contact);
}
} else if (msg[0].type === SFU_INTERNAL.CONTACT_REMOVED) {
if(!promises.resolve(msg[0].internalMessageId, msg[0].contact)) {
notify(SFU_EVENT.CONTACT_REMOVED, msg[0].contact);
}
} else if (msg[0].type === SFU_INTERNAL.CHAT_DELETED) {
notify(SFU_EVENT.CHAT_DELETED, msg[0].info);
} else if (msg[0].type === SFU_INTERNAL.CHAT_UPDATED) {
promises.resolve(msg[0].internalMessageId, msg[0].info);
notify(SFU_EVENT.CHAT_UPDATED, msg[0].info);
} else if (msg[0].type === SFU_INTERNAL.USER_CHATS) {
promises.resolve(msg[0].internalMessageId, msg[0].chats);
notify(SFU_EVENT.USER_CHATS, msg[0].chats);
} else if (msg[0].type === SFU_INTERNAL.PUBLIC_CHANNELS) {
promises.resolve(msg[0].internalMessageId, msg[0].channels);
notify(SFU_EVENT.PUBLIC_CHANNELS, msg[0].channels);
} else if (msg[0].type === SFU_INTERNAL.CHAT_LOADED) {
promises.resolve(msg[0].internalMessageId, msg[0].chat);
notify(SFU_EVENT.CHAT_LOADED, msg[0].chat);
} else if (msg[0].type === constants.SFU_ROOM_EVENT.OPERATION_FAILED && promises.promised(msg[0].internalMessageId)) {
promises.reject(msg[0].internalMessageId, msg[0]);
} else if (msg[0].type === constants.SFU_EVENT.ACK && promises.promised(msg[0].internalMessageId)) {
promises.resolve(msg[0].internalMessageId);
} else if (msg[0].roomName && msg[0].roomName.length > 0) {
//room event
const room = rooms[msg[0].roomName];
if (room) {
room.processEvent(msg[0]);
}
} else {
notify(msg[0].type, msg[0]);
}
break;
case "failed":
notify(constants.SFU_EVENT.FAILED, msg[0]);
break;
}
};
connection.onClose = function(e) {
state = SFU_STATE.DISCONNECTED;
disconnect();
notify(SFU_EVENT.DISCONNECTED, e);
};
connection.onError = function(e) {
state = SFU_STATE.FAILED;
notify(SFU_STATE.FAILED, e);
};
}
/**
* Connect to server.
*
* @param {Object} options SFU options
* @param {String} options.url Server url
* @param {String} options.username Username
* @param {String} options.password Password
* @param {String=} options.nickname Participant's nickname
* @returns {Promise<void|Error>} Promise which resolves upon connect
* @throws {TypeError} Error if no options provided
* @memberof FlashphonerSFUExtended
*/
const connect = function(options) {
if (!options) {
throw new TypeError("No options provided");
}
logger.setPrefix(() => {
return options.username;
});
setupConnection(connection);
server = new URL(options.url).hostname;
connectionConfig = {
url: options.url,
appName: SFU_INTERNAL.Z_APP,
custom: {
username: options.username,
password: options.password,
nickname: options.nickname
}
};
return new Promise(function(resolve, reject) {
if (state !== SFU_STATE.NEW && state !== SFU_STATE.DISCONNECTED && state !== SFU_STATE.FAILED) {
reject(new Error("Can't connect with the state " + state));
return;
}
connection.connect(connectionConfig).then(function (connectionConfig) {
user = Object.freeze({
username: connectionConfig[0].sipLogin,
nickname: connectionConfig[0].sipVisibleName,
pmi: connectionConfig[0].pmi
});
state = SFU_STATE.AUTHENTICATED;
notify(SFU_EVENT.CONNECTED);
resolve(user);
}, function (e) {
state = SFU_STATE.FAILED;
notify(SFU_EVENT.FAILED, e);
reject(e);
});
});
};
/**
* @typedef MessageAttachment
* @memberOf FlashphonerSFUExtended
* @property attachment {Object} attachment info
* @property attachment.type {String} "file|picture"
* @property attachment.name {String} name of the attachment
* @property attachment.size {Number} payload size
* @property attachment.payload {String} base64 string that represents content of the attachment
*/
/**
* Send message
* @param {Object} msg Message
* @param {String} msg.to Recipient's id (deprecated, use chatId instead)
* @param {String} msg.chatId Indicates chat this message belongs to
* @param {String} msg.body Message body
* @param {Array<MessageAttachment>} msg.attachments
* @returns {Promise} Promise will resolve upon message delivery and reject if delivery was unsuccessful
* @throws {Error} error if api isn't connected
* @memberOf FlashphonerSFUExtended
*/
const sendMessage = function(msg) {
if (state !== SFU_STATE.AUTHENTICATED) {
throw new Error("Can't send message while in " + state + " state");
}
return new Promise(function(resolve, reject) {
//validate
if (!msg) {
reject(new Error("Can't send null message"));
} else if ((!msg.body || msg.body === "") && (!msg.attachments || msg.attachments.length === 0)) {
reject(new Error("Can't send message without content"));
} else if (!msg.chatId || msg.chatId === "") {
reject(new Error("Can't send message without a chatId"));
} else {
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.SEND_MESSAGE, {
id: id,
internalMessageId: id,
to: msg.to,
body: msg.body,
chatId: msg.chatId,
attachments: msg.attachments
});
}
});
};
/**
<<<<<<< HEAD
* Mark message
* @param {Object} msg Message
* @param {String} msg.id Message id
* @param {String} msg.chatId Indicates chat this message belongs to
* @returns {Promise} Promise resolves with a new state
* @throws {Error} error if api isn't connected
=======
* Fetch available user list from server
* @returns {Promise<Array<FlashphonerSFUExtended.UserListEntry>>}
>>>>>>> zapp-26
* @memberOf FlashphonerSFUExtended
*/
const markMessageRead = function(msg) {
if (state !== SFU_STATE.AUTHENTICATED) {
throw new Error("Can't mark message while in " + state + " state");
}
return new Promise(function(resolve, reject) {
if (!msg) {
reject(new Error("Can't mark null message"));
} else if (!msg.chatId || msg.chatId === "") {
reject(new Error("Can't mark message without a chatId"));
} else if (!msg.id || msg.id === "") {
reject(new Error("Can't mark message without massage id"));
} else {
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.MARK_MESSAGE_READ, {
internalMessageId: id,
id: msg.id,
chatId: msg.chatId
});
}
});
}
/**
* Mark message
* @param {Object} msg Message
* @param {String} msg.id Message id
* @param {String} msg.chatId Indicates chat this message belongs to
* @returns {Promise} Promise resolves with a new state
* @throws {Error} error if api isn't connected
* @memberOf FlashphonerSFUExtended
*/
const markMessageUnread = function(msg) {
if (state !== SFU_STATE.AUTHENTICATED) {
throw new Error("Can't mark message while in " + state + " state");
}
return new Promise(function(resolve, reject) {
if (!msg) {
reject(new Error("Can't mark null message"));
} else if (!msg.chatId || msg.chatId === "") {
reject(new Error("Can't mark message without a chatId"));
} else if (!msg.id || msg.id === "") {
reject(new Error("Can't mark message without massage id"));
} else {
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.MARK_MESSAGE_UNREAD, {
internalMessageId: id,
id: msg.id,
chatId: msg.chatId
});
}
});
}
/**
* Fetch available user list from server
* @returns {Promise<Array<FlashphonerSFUExtended.UserListEntry>>}
* @memberOf FlashphonerSFUExtended
*/
const getUserList = function() {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't get user list while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.GET_USER_LIST, {internalMessageId: id});
});
};
/**
* Fetch available calendar from server
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const getUserCalendar = function() {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't get user calendar while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.GET_USER_CALENDAR, {internalMessageId: id});
});
};
/**
* Add event to the calendar
* @param event {FlashphonerSFUExtended.UserCalendarEvent}
* @returns {Promise<void|error>}
* @memberOf FlashphonerSFUExtended
*/
const addCalendarEvent = function(event) {
return new Promise(function(resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't add calendar event while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.ADD_CALENDAR_EVENT, {
internalMessageId: id,
event: event
});
});
};
/**
* Remove event from the calendar
* @param event {FlashphonerSFUExtended.UserCalendarEvent}
* @returns {Promise<void|error>}
* @memberOf FlashphonerSFUExtended
*/
const removeCalendarEvent = function(event) {
return new Promise(function(resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't remove calendar event while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.REMOVE_CALENDAR_EVENT, {
internalMessageId: id,
event: event
});
});
};
/**
* Fetch available chats from server
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const getUserChats = function() {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't get user chats while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.GET_USER_CHATS, {internalMessageId: id});
});
};
const getPublicChannels = function() {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't get public channels while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.GET_PUBLIC_CHANNELS, {internalMessageId: id});
});
};
/**
* Fetch chat data from server
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const loadChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't load chats while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.LOAD_CHAT, {id: chat.id, internalMessageId: id});
});
};
/**
* Create chat
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const createChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't create chats while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.CREATE_CHAT, {
id: chat.id,
name: chat.name,
members: chat.members,
favourite: chat.favourite,
internalMessageId: id,
channel: chat.channel,
channelType: chat.channelType,
channelSendPolicy: chat.channelSendPolicy,
sendPermissionList: chat.sendPermissionList
});
});
};
/**
* Delete chat
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const deleteChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't delete chats while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.DELETE_CHAT, {id: chat.id, internalMessageId: id});
});
};
/**
* Rename chat
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const renameChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't rename chats while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.RENAME_CHAT, {id: chat.id, name: chat.name, internalMessageId: id});
});
};
/**
* Add member to chat
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const addMemberToChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't add member to chat while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.ADD_MEMBER_TO_CHAT, {id: chat.id, member: chat.member, internalMessageId: id});
});
};
/**
* Remove member from chat
* @returns {Promise<Array<FlashphonerSFUExtended.UserCalendar>>}
* @memberOf FlashphonerSFUExtended
*/
const removeMemberFromChat = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't remove member to chat while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.REMOVE_MEMBER_FROM_CHAT, {id: chat.id, member: chat.member, internalMessageId: id});
});
};
/**
*
* @param invite
* @returns {Promise<unknown>}
*/
const inviteContact = function(invite) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't invite contact while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.INVITE_CONTACT, {from: user.username, to: invite.to, internalMessageId: id});
});
}
/**
*
* @param invite
* @returns {Promise<unknown>}
*/
const confirmContact = function(invite) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't confirm contact while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.CONFIRM_CONTACT, {from: invite.from, to: invite.to, id: invite.id, internalMessageId: id});
});
}
/**
*
* @param contact
* @returns {Promise<unknown>}
*/
const removeContact = function(contact) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't remove contact while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.REMOVE_CONTACT, {id: contact.id, internalMessageId: id});
});
}
/**
*
* @param channel
* @returns {Promise<unknown>}
*/
const updateChannelSendPolicy = function(channel) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't change channel send policy while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.UPDATE_CHANNEL_SEND_POLICY, {
id: channel.id,
channelSendPolicy: channel.channelSendPolicy,
internalMessageId: id
});
});
}
const addChannelSendPermissionListMember = function(channel) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't change channel send permission list while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.ADD_CHANNEL_SEND_PERMISSION_LIST_MEMBER, {
id: channel.id,
member: channel.member,
internalMessageId: id
});
});
}
const removeChannelSendPermissionListMember = function(channel) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't change channel send permission list while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.REMOVE_CHANNEL_SEND_PERMISSION_LIST_MEMBER, {
id: channel.id,
member: channel.member,
internalMessageId: id
});
});
}
const addChatToFavourites = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't add to favourites while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.ADD_CHAT_TO_FAVOURITES, {
id: chat.id,
internalMessageId: id
});
});
}
const removeChatFromFavourites = function(chat) {
return new Promise(function (resolve, reject){
if (state !== SFU_STATE.AUTHENTICATED) {
reject(new Error("Can't remove from favourites while in " + state + " state"));
return;
}
const id = uuidv4();
promises.add(id, resolve, reject);
connection.send(constants.SFU_INTERNAL_API.REMOVE_CHAT_FROM_FAVOURITES, {
id: chat.id,
internalMessageId: id
});
});
}
/**
* Create room
*
* @param {Object} options Room options
* @param {String} options.name Room name
* @param {String} options.pin Room's pin
* @param {Object} options.pc Peer connection
* @returns {FlashphonerSFU.Room} Room
* @throws {TypeError} Error if no options provided
* @throws {Error} error if api isn't connected
* @memberof FlashphonerSFUExtended
*/
const room = function(options) {
if (!options) {
throw new TypeError("No options provided");
}
if (state !== SFU_STATE.AUTHENTICATED) {
throw new Error("Can't create room while in " + state + " state");
}
const opt = {
connection: connection,
name: options.name,
pin: options.pin,
pc: options.pc
};
const exports = roomApi.room(opt);
rooms[options.name] = exports;
const cleanup = function() {
rooms[options.name].pc().close();
rooms[options.name].pc().dispatchEvent(new Event("connectionstatechange"));
delete rooms[options.name];
};
exports.on(constants.SFU_ROOM_EVENT.LEFT, function(participant){
if (participant.name === user.nickname) {
cleanup();
}
}).on(constants.SFU_ROOM_EVENT.EVICTED, function(participant) {
if (participant.name === user.nickname) {
cleanup();
}
}).on(constants.SFU_ROOM_EVENT.FAILED, cleanup
).on(constants.SFU_ROOM_EVENT.OPERATION_FAILED, function(e) {
if (constants.SFU_OPERATIONS.ROOM_JOIN === e.operation) {
cleanup();
}
});
return exports;
};
/**
* Get previously created room.
* Note that this function will not return ended or failed room
*
* @param options {Object}
* @param options.name {String} room name
* @returns {FlashphonerSFU.Room} Room
* @throws {TypeError} Error if no options provided
* @throws {Error} error if api isn't connected
* @memberof FlashphonerSFUExtended
*/
const getRoom = function(options) {
if (!options) {
throw new TypeError("No options provided");
}
if (state !== SFU_STATE.AUTHENTICATED) {
throw new Error("Can't create room while in " + state + " state");
}
return rooms[options.name];
}
/**
* FlashphonerSFUExtended event callback.
*
* @callback FlashphonerSFUExtended~eventCallback
* @param {FlashphonerSFUExtended} sdk instance FlashphonerSFUExtended
*/
/**
* Add session event callback.
*
* @param {String} event One of {@link FlashphonerSFU.SFU_EVENT} events
* @param {FlashphonerSFUExtended~eventCallback} callback Callback function
* @returns {FlashphonerSFUExtended} SDK instance callback was attached to
* @throws {TypeError} Error if event is not specified
* @throws {Error} Error if callback is not a valid function
* @memberOf FlashphonerSFUExtended
*/
const on = function (event, callback) {
if (!event) {
throw new TypeError("Event can't be null");
}
if (!callback || typeof callback !== "function") {
throw new Error("Callback needs to be a valid function");
}
if (!callbacks[event]) {
callbacks[event] = [];
}
callbacks[event].push(callback);
return sfu;
};
/**
* Remove session event callback.
*
* @param {String} event One of {@link FlashphonerSFU.SFU_EVENT} events
* @param {FlashphonerSFUExtended~eventCallback} callback Callback function
* @returns {FlashphonerSFUExtended} SDK instance callback was removed from
* @throws {TypeError} Error if event is not specified
* @throws {Error} Error if callback is not a valid function
* @memberOf FlashphonerSFUExtended
*/
const off = function (event, callback) {
if (!event) {
throw new TypeError("Event can't be null");
}
if (!callback || typeof callback !== "function") {
throw new Error("Callback needs to be a valid function");
}
if (!callbacks[event]) {
callbacks[event] = [];
}
let index = callbacks[event].findIndex(element => element === callback);
if (index !== -1) {
callbacks[event] = callbacks[event].slice(index, 1);
}
return sfu;
};
const notify = function(event, msg) {
if (callbacks[event]) {
for (const callback of callbacks[event]) {
callback(msg);
}
}
};
/**
* Disconnect sfu from the server
* @memberOf FlashphonerSFUExtended
*/
const disconnect = function() {
for (const [key, value] of Object.entries(rooms)) {
value.leaveRoom();
}
user = undefined;
connection.close();
connection = ws.createConnection();
state = SFU_STATE.DISCONNECTED;
rooms = {};
};
sfu.on = on;
sfu.off = off;
sfu.connect = connect;
sfu.sendMessage = sendMessage;
sfu.markMessageRead = markMessageRead;
sfu.markMessageUnread = markMessageUnread;
sfu.getUserList = getUserList;
sfu.getUserCalendar = getUserCalendar;
sfu.addCalendarEvent = addCalendarEvent;
sfu.removeCalendarEvent = removeCalendarEvent;
sfu.getUserChats = getUserChats;
sfu.getPublicChannels = getPublicChannels;
sfu.loadChat = loadChat;
sfu.createChat = createChat;
sfu.deleteChat = deleteChat;
sfu.renameChat = renameChat;
sfu.addMemberToChat = addMemberToChat;
sfu.removeMemberFromChat = removeMemberFromChat;
sfu.inviteContact = inviteContact;
sfu.confirmContact = confirmContact;
sfu.removeContact = removeContact;
sfu.updateChannelSendPolicy = updateChannelSendPolicy;
sfu.addChannelSendPermissionListMember = addChannelSendPermissionListMember;
sfu.removeChannelSendPermissionListMember = removeChannelSendPermissionListMember;
sfu.addChatToFavourites = addChatToFavourites;
sfu.removeChatFromFavourites = removeChatFromFavourites;
sfu.room = room;
sfu.getRoom = getRoom;
/**
* @typedef {Object} SFUUser
* @property username {String} username
* @property nickname {String} nickname
* @memberOf FlashphonerSFUExtended
*/
/**
* Get current user
* @returns {FlashphonerSFUExtended.SFUUser} Returns current logged in user
* @memberOf FlashphonerSFUExtended
*/
sfu.user = function(){
return user;
};
/**
* Get hostname of the server in use
* @returns {String} Current server's hostname
* @memberOf FlashphonerSFUExtended
*/
sfu.server = function() {
return server;
};
sfu.disconnect = disconnect;
/**
* Get sfu state
* @returns {FlashphonerSFU.SFU_STATE} Current sfu state
*/
sfu.state = function() {
return state;
};
sfu.constants = constants;
module.exports = sfu;