The basic functions are compatible with IE8+ and various modern browsers of latest version, including Chrome, FireFox, Safari, and so forth.
The recording and sending of audio and video messages in Chat mode only supports Chrome and Firefox.
This guide only provides a brief integration description. For more details on the usage, see API Documentation.
Download from Here, or install using bower:
bower install tuisongbao-realtime-engine-client
Then reference to engine.js
or engine.min.js
under the installation directory:
<script src="/path/to/engine.min.js"></script>
Engine.debug.enable('engine:*')
in Console, the browser development tool to turn on the debug log, and run Engine.debug.disable()
to turn it off.Pass various options through the second parameter while instantiating Engine
:
var options = {
// Authenticate user address
authEndpoint: 'http://yourdomain.com/tuisongbao_engine/auth',
// Authenticate user request method, `xhr` by default, which uses XMLHttpRequest, but this method has cross-domain problem on IE8/9. If the authEndpoint you configured is cross domain and needs to support IE8/9, you should use `jsonp` and meanwhile please ensure your server supports the `jsonp` requests. This setting will take effect on all browsers, not only on IE 8/9
authTransport: 'jsonp',
// Optional, if configured, the authentication request will carry this value to demonstrate user identity. When used together with jsonp, if the value is Object, it will be serialized into JSON string
authData: 'authData-sample'
// When using extensions (Chat local cache and multimedia message), you must specify the parent path on the Web server for "engine.js"
basePath: '/engine/clientJavaScript/',
// Optional, the role is that SDK can support the invocation of certain APIs when the network is not available. For more details, see Cache Policy in chapter Chat.
supportOffline: true,
// Chat related options, no need to configure them if the Chat mode is not used
chat:
// Enable local cache, which supports Chrome, Firefox and IE11
enableCache: true,
// Enable the delivery function of multimedia messages (images, audios and videos). Enabling this option will also load additional resouce files asynchronously
enableMediaMessage: true
};
var engine = new Engine('YOUR_APP_ID', options);
After instantiation, connection will be automaticalled established, and you can use the Engine
instance that is returned for later various operations.
You can listen for the following Events on the engine.connection
object:
state_changed
: Triggered when connect state is changed.connecting_in
: Notify how soon the next reconnection will be made.initialized
, connected
, disconnected
, connecting
and failed
are triggered respectively when Connection
enters the corresponding states.error
: Triggered when an error occurs.connection.bind('state_changed', function (states) {
console.log(states.previous, states.current);
});
connection.bind('connecting_in', function (delay) {
console.log('Reconnection will be made' + delay + 'ms later');
});
connection.bind('connecting', function () {
// Prompt the user that the network is unstable and it is trying to make a connection
});
connection.bind('error', function (err) {
console.log(err);
});
connection.bind('connected', function () {
console.log(connection.socketId);
});
Call disconnect
on the connection
object:
connection.disconnect();
To restore a connection, call connect
:
connection.connect();
The Pub/Sub related functions are mainly completed through engine.channels
.
var channels = engine.channels;
var coolChannel = channels.subscribe('cool-channel');
This method will return the Channel
instance, which can be used for such operations as bind
, and so on.
Additionally, you can get the Channel
instance that has been subscribed through the find
method of channels
:
var coolChannel = channels.find('cool-channel');
Unsubscribe though the unsubscribe
method:
channels.unsubscribe('cool-channel');
coolChannel.bind('cool-event', function (data) {
// processing logic
});
This operation is only applied to the current Channel
, that is to say you can use the same Event name on other Channels
.
Unbind through the unbind
method:
// Only unbind a certain handler of this Event
coolChannel.unbind('cool-channel', handler);
// Unbind all the handlers of this Event
coolChannel.unbind('cool-channel');
All the Channels
can handle the subscription result by listening for the engine:subscription_succeeded
and engine:subscription_error
Event:
privateChannel.bind('engine:subscription_succeeded', function () {
console.log('subscription channel ' + privateChannel.name + ' successful');
});
privateChannel.bind('engine:subscription_error', function (err) {
console.log('subscription channel ' + privateChannel.name + ' failed', err);
// Re-subscribe ?
});
As for Presence Channel and engine:subscription_succeeded
, the handler will get an extra parameter users
, and this object has the following attributes:
{
// The number of users who are online currently on this Channel
count: 100,
// Receive a method as a parameter to be used to traverse current online users
each: [Function],
// Current users
me: {
id: '1111',
info: 'Fake user info for socket 111111 on channel presence-demo'
}
}
An example is shown below:
presenceChannel.bind('engine:subscription_succeeded', function (users) {
console.log('subscription channel ' + presenceChannel.name + ' successful');
console.log('number of users:' + users.count);
console.log('Traversing users starts:');
users.each(function (user) {
console.log(user.id, user.info);
});
console.log('Traversing users ends');
console.log('Current users:', users.me.id, users.me.info);
});
Note that the users
object can also be obtained directly on the Presence Channel object:
console.log(presenceChannel.users);
In addition, you can listen for engine:user_added
and engine:user_removed
on the Presence Channel object to handle notifications of users’ coming online or going offline:
presenceChannel.bind('engine:user_added', function (user) {
console.log('new user:', user.id, user.info);
});
presenceChannel.bind('engine:user_removed', function (user) {
console.log('The user went offline:', user.id, user.info);
});
The Chat related functions are mainly completed through engine.chatManager
.
chatManager.bind('login:succeeded', function() {
console.log('Successfully signed in');
});
chatManager.bind('login:failed', function(err) {
console.log('Failed to sign in');
});
chatManager.bind('message:new', function(message) {
console.log('New message');
});
For more Events, see API Documentation.
chatManager.login({
authData: chatUserId
});
var onLoginSucceeded = function() {
console.log('login succeeded');
};
var onLoginError = function(err) {
console.log('login failed:', err);
};
engine.chatManager.bind('login:succeeded:', onLoginSucceeded);
engine.chatManager.bind('login:failed:', onLoginError);
chatManager.logout().then(function() {
console.log('Successfully signed out');
}).catch(function(err){
console.log('Failed to sign out' + err);
});
// The content is the userData that is returned by your server when authenticating users
console.log(engine.chatManager.user);
// Enumeration values: initialized, loggingIn, loggedIn, failed, loggedOut
console.log(engine.chatManager.state);
Get the conversation list through chatManager.conversations
.
Promise use:
conversations.load().then(function(conversations) {
console.log('Successfully got the list of the Conversation instance');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
Callback use
conversations.load({
onSuccess: function(conversations) {
console.log('Successfully got the list of the Conversation instance');
},
onError: function(err) {
console.log('Failed to get. Please try later');
}
});
For the description of Promise and Callback, see Here.
Developers can call the methods on the ChatConversation
instance to send messages, delete conversations, reset unread messages, and so forth. It can be obtained from the coversation list as mentioned in the above example, or you can acquire a specific conversation through conversations.loadOne
:
conversations.loadOne({
type: 'singleChat',
target: '1111'
}).then(function(_conversation) {
conversation = _conversation
});
conversation.loadMessages({
// Conversation type, singleChat(single chats)or groupChat(group chats)
type: 'singleChat',
// With who (the ID of chat counterpart), userId or groupId
target: '1111',
// Optional
startMessageId: 100,
// Optional
endMessageId: 300,
// Optional, 20 by defaut, a max of 100 is allowed
limit: 20
// Please refer to the API documentation for other parameters
}).then(function(messages) {
console.log('Successfully got conversation messages');
// When the support of offline function is enabled, the messages stored offline have three states, including `sending`, `succeeded` and `failed`. When the state is `sending`, messages will be resent before calling loadMessages, during which the message state may be changed. If you want to trace the message state, you can listen for the `state:changed` event
messages.map(function (message){
if(message.state !== 'succeeded'){
message.bind('state:changed', function (state){
// Message state is changed, and the logic of refreshing UI can be coded here
console.log("State before change:", state.previous);
console.log("Curtrent state", state.current);
});
}
});
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
conversation.resetUnread();
conversation.delete().then(function() {
console.log('Successfully deleted the conversation');
}).catch(function(err) {
console.log('Failed to delete. Please try later');
});
Listen for new messages by listening for message:new
Event on the ChatConversation
object:
conversation.bind('message:new', function(newMessage) {
console.log('You received from' + newMessage.from + 'a new message');
// type enumerations: 'text', 'image', 'voice', 'video', 'location', 'event'
console.log('The message type is:' + newMessage.content.type);
if (newMessage.content.file) {
console.log('Address of multimedia file download:' + newMessage.content.file.url);
console.log('Size of multimedia file:' + newMessage.content.file.size);
} else if (newMessage.content.location) {
console.log('The location (point of interest) is:' + newMessage.content.location.poi);
} else if (newMessage.content.event) {
console.log(' Event type:' + newMessage.content.event.type);
} else {
console.log('What you sent is text message, and content is:' + newMessage.content.text);
}
console.log('Additional information:' + newMessage.content.extra);
console.log('Delivery Time:' + newMessage.createdAt);
});
conversation.sendMessage({
type: 'text',
text: 'Hello World!',
// Optional, addition information, used to implement custom business logic of the application
extra: {}
}).then(function(message) {
console.log(message);
}).catch(function(err) {
console.log('Failed to send. Please try later');
});
conversation.getImageUploader({
// Trigger the ID of the DOM element selected by a file
browseButton: 'imageMessage',
// Optional, dragging the ID of the DOM element of an area can implement drag and upload
dropElementId: 'messageContainer',
// Optional, additional information, used to implement custom business logic of the application
extra: {}
}).then(function(imageUploader) {
console.log('Successfully got imageUploader,and you can listen for Event on it');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
After initialization, clicking browseButton
will pop up the file selection dialog, and after selecting a file, the file will be automatically uploaded and the message will be sent.
imageUploader.bind('failed', function(err) {
console.log('imageUploader initialization failed:' + err);
});
imageUploader.bind('message:sent', function(sentMessage) {
console.log('Image message sent successfully:' + sentMessage);
});
imageUploader.bind('message:sendFailed', function(err) {
console.log('Image message sending failed:' + err);
});
imageUploader.bind('state:changed', function(state) {
// The value of the state may be: initialized(Initialization complete),uploaded(Uploaded successfully ),uploading(Is uploading),failed(Initialization failed)
console.log('The state of uploading image messages:' + state);
});
// Unbind all the handlers of this Event and destroy the imageUploader object as well as the DOM nodes selected by the corresponding files
imageUploader.destroy()
Audio message sending is completed through VoiceUploader
.
VoiceUploader
provides a set of methods of sending audio messages. For more details, see API](docs/engineAPI/clientJavaScript/index.html#ChatVoiceUploader).
startRecord
: Begin to record an audiostopRecord
: Stop recording a audiosend
: Send an audio recordedconversation.getVoiceUploader({
// Optional, additional information, used to implement custom business logic of the application
extra: {}
}).then(function(voiceUploader) {
console.log('Successfully got voiceUploader,and you can listen for Event on it');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
voiceUploader.bind('failed', function(err) {
console.log('VoiceUploader initialization failed:' + err);
});
voiceUploader.bind('message:sent', function(sentMessage) {
console.log('Audio message sent successfully:' + sentMessage);
});
voiceUploader.bind('message:sendFailed', function(err) {
console.log('Audio message sending failed:' + err);
});
voiceUploader.bind('state:changed', function(state) {
// The value of the state may be: initialized(Initialization complete),recording(Is recording),recorded(Recorded successfully),uploaded(Uploaded successfully),uploading(Is uploading),failed(Initialization failed)
console.log('The state of rcording and uploading audio messages:' + state);
});
voiceUploader.bind('record:started', function() {
console.log('Recording started');
});
voiceUploader.bind('record:stopped', function(blob, duration) {
console.log('Recording ended, and return the blob object as well as length');
});
// Unblind all the handlers of this Event, and destroy the voiceUploader object
voiceUploader.destroy()
Video message sending is completed through VideoUploader
.
VideoUploader
provides a set of methods of sending video messages. For more details, see API.
startRecord
: Start to record a videostopRecord
: Stop recording a videosend
: Send a video recordedconversation.getVideoUploader().then(function(videoUploader) {
console.log('Successfully got videoUploader, and you can listen for the Event on it');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
videoUploader.bind('failed', function(err) {
console.log('VideoUploader initialization failed:' + err);
});
videoUploader.bind('message:sent', function(sentMessage) {
console.log('Video message sent successfully:' + sentMessage);
});
videoUploader.bind('message:sendFailed', function(err) {
console.log('Video message sending failed:' + err);
});
videoUploader.bind('state:changed', function(state) {
// The value of the state may be: initialized(Initialization complete),recording(Is recording),recorded(Recorded successfully),uploaded(Uploaded successfully),uploading(Is uploading),failed(Initialization failed)
console.log('The state of recording and uploading video messages:' + state);
});
voiceUploader.bind('record:started', function() {
console.log('Recording started');
});
videoUploader.bind('record:stopped', function(blob, duration) {
console.log('Recording ended, and return the blob object as well as length');
})
// Unbind all the Events, and destroy the videoUploader object as well as the DOM nodes of the corresponding video recording
videoUploader.destroy()
chatManager.locationHelper.getLocation().then(function(location) {
// Return the longitude and latitude of the current location
console.log('The current location is:' + location);
// Send location data messages
conversation.sendMessage({
type: 'location',
location: {
// Latitude
lat: location.lat
// Longitude
lng: location.lng
// Optional, point of interest, if not provided, TuiSongBao will attempt to get it from Baidu Maps
poi: location.poi
},
// Optional, additional information, used to implement the custom business logic of the application
extra: {}
}).then(function(message) {
console.log(message);
}).catch(function() {
console.log('Failed to send. Please try later');
});
}).catch(function(err) {
console.log('err: ' + err);
});
You can get the group list through chatManager.groups
:
// Have no parameters, and this interface is used to sync up the latest group list
chatManager.groups.load({
// Optional, filter according to ID
groupId: '54c4951f50c5e752c0a512a1'
}).then(function(groups) {
console.log(groups);
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
chatManager.groups.create({
// Whether a group is public (true: The request for joining a group from any user will be directly passed without verification; false: Need the administrator to verify)
isPublic: true,
// Except the creator (owner), whether other group users can send invitations to join the group (true: allowed; false: not allowed)
userCanInvite: true
// Original members, if successfully created, group invitations will be sent to these users, if acceptAllJoinGroupInvitation of an invitee is true, he or she can directly join the group
inviteUserIds: ['1111', '2222']
}).then(function(_group) {
group = _group;
}).catch(function(err) {
console.log('Failed to create. Please try later');
});
group.loadUsers().then(function(users) {
console.log('Successfully got group users');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
Structure of users
:
[{
userId: '1111',
// Online state, online or offline
presence: 'online'
}]
group.inviteUsers({
userIds: ['1111']
}).then(function() {
console.log('Successfully got the group users');
}).catch(function(err) {
console.log('Failed to get. Please try later');
});
group.removeUsers({
userIds: ['1111']
}).then(function(users) {
console.log('Successfully removed users');
}).catch(function(err) {
console.log('Failed to remove. Please try later');
});
group.leave().then(function() {
console.log('Successfuly left the group');
}).catch(function(err) {
console.log('Failed to leave. Please try later');
});
All the methods support the two asynchronous invocations of promise
and callback in ChatManager
except login
. For more details, see [API Documentation] (docs/engineAPI/clientJavaScript/).
ChatManager
, ChatConversation
, ChatUploader
, and so on are all inherited from EventEmitter, so the bind
method can be used on all these objects to bind event handlers as well as the unbind
method to unbind event handlers.
All message types support “extra” to implement the custom business logic of the application.
Sending audio, video and location data messages needs to request the browser for the corresponding permissions. SDK will send the request to the browser in due time, and only after users consent can the messages be sent.
If no special notes, just replacing the SDK would be enough.
engine.channels
ChatManager
, all the APIs are delivered to each sub module based on the function except login
and logout
. For more details, see [API Documentation] docs/engineAPI/clientJavaScript/).chatManager
:chatManager.loggedIn
, and added chatManager.state