advanced chat

introduction

Lets go deeper and create a telegram like app, unlike the previous example we will be using a framework (svelte). we will not explain each line but instead explain only necessary points, grab the code and follow along.

features

these are the features we are going to add to our example

  1. sending and receiving various message types across channels | groups
  2. channel management, create, add users, moderate users, remove users, etc
  3. calls private calls, group calls, broadcasts and streaming

routes

we have 3 routes in the src/routes directory.

  1. /user - authorize users
  2. / - main chat page
  3. /new - create new channels and join open channels

authorization

For simplicity we are storing user information in the local storage. onMount we are first check if there is the user key in local storage and if not redirect user to the /user page where they put in their details (name and id) and redirect them back to / where they connect to cyxth.

login

connect to cyxth

Once we have collected the user info and saved it to localStorage. we call getToken() from the previous example that fetches token data which we connect() to our cyxth instance.

If connect() was successiful we get the user’s persistent channels using the channels.list() function. this function only gets the user’s channel information such as avatar,name and metadata.if user has no channels they are redirected to /new page where the can create and join channels.

To get messages and activity across all user channels we use the channels.getMessages() function with a specific start time or start message id usually the last message the user saw if offline is enabled. this will send the first 100 messages across all channels.

// start date
let channelActivity = await cyxth.channels.getMessages('7085164563653595136');

this returns messages grouped by channel starting from the given date or message id.

[
	{
		"breakout": [
			{
				messageId: '7085164563653595136',
				type: 'message',
				userId: 'bob',
				timestamp: 'Date',
				content: {
					text: 'hello',
					media: {
						pictures: [
							{
								name: 'hello',
								url: 'https://imgs.cyxth.com/xyz/1234',
								thumb: 'https://imgs.cyxth.com/xyz/1234'
							},
							...
						]
					}
				},
				channelId: 'breakout'
			},
			...
		],
		"helloworld":[...],
		...
	}
];

on getting this information we can display the channel list and show last message and unread count.

channel list

It is recommended to enable offline option on cyxth initialization. to enable local cache using IndexedDb if you are building a chat application similar to this one.

let cyxth = new Cyxth(APP_URL, {
	offline: true
});

messaging

once we have listed the channels on clicking any channel we can see all messages and send new messages. new messages are added to the channel’s messages object. on new message received we add it to the respective channel too and update unread count if user is currently not viewing the current channel.

const sendMessage = async (message) => {
	cyxth
		.send(channelId, message)
		.then((sent) => {
			// update message sent or delivery status
		})
		.catch((err) => {
			// handle error
		});

	updateMessages(message);
};

cyxth.on('message', (message) => updateMessages(message));
cyxth.on('activity', (activity) => showChannelActivity(activity));

we don’t have wait for the message to be delivered to add it to the ui. we instead update the message status to sent,failed or delivered later. this might not be your case and you may need to wait for delivery status if you’d like to use the new message id.

edit and react to messages

cyxth supports editing and reacting to messages, all you just need is to provide the messageId of the message you’d wish to modify and new content. in this example by right clicking the user can edit,delete,reply and react to a given message. check the message documentation to find out more.

channel activity

channel activity includes when a user joins, leaves, is blocked, is made admin and many more. this event can be listened for and show relevant information. in this example we add them as special messages in channels, activity can be private visible to only a given user or public visible to all users in the channel depending on the channel or application level activity setting.

cyxth.on('activity', (activity) => showChannelActivity(activity));

full chat

i’ve went ahead and added emoji,gif and sticker functionality and file sharing in the same page check out the source code for more.

calls

intergrating calls to cyxth is easy with the @cyxth/calls npm package. calls can utilize the existing channel or create a new temporary call channel shared in the same parent channel or any other means (you can create a call link externally too). for our case we are just going to build calls on top of existing persistent channels . Go ahead and install the @cyxth/calls npm module and add this to your cyxth initialization.

import Calls from '@cyxth/calls';

let cyxth = new Cyxth(APP_URL, {
	offline: true,
	calls: Calls
});

starting a call

cyxth supports private calls (one to one), group calls(many to many), broadcast (few to many), streams (one to many) and every thing in between, you can start at any of the calls and upgrade or downgrade to another.

for this implementation to start a call users click the call button in the far right corner in any channel.

const call = async () => {
	let call = await cyxth.startCall('channel_id', {
		video: true,
		audio: true
	});

	handleCall(call);
};

cyxth.on('call', async (data) => {
	// show a notification | ring
	//add logic to accept or reject the call
	let call = await data.request.accept({
		video: true,
		audio: true
	});

	handleCall(call);
});

read more on call configuration.

call events

In our handleCalls() function we listen for call events connected, join, leave, end and update and update the call interface. to listen just add.

const handleCall = async (call) => {
	call.on('join', (data) => {
		// add user element
	});

	call.on('leave', (data) => {
		// remove user
	});

	call.on('end', (data) => {
		// show end or smth
	});

	call.on('update', (data) => {
		if (data.action === 'toggle-mute') {
			// update interface
		} else if (data.action === 'toggle-on-off') {
			//
		}
		// ....
	});

	// more events
};

read more on call events.

call methods

Beside listening for call events. you can toggle mic, toggle video and leave among other call methods. In this example we have various ui elements to share screen, mute button for mute() and unmute() video toggle for enabling and disabling video stream that call cameraOn() and cameraOff() methods and finally leave to leave() the call / meeting.

read more on call methods.

channels

on /new page we first list all open channels using channels.list(). this method returns all channels marked as public. we also add a button to create new channels using channels.create(). the user has to have the permissions to create channel to do this. users can also join any channel using channels.join() and list channel users using channels.getMembers() method.

next client guide