существуетПредыдущий контентВ книге автор monkeyHi поделился основным использованием и возможными сценариями Agora signaling SDk, а также проанализировал принцип интерфейса демонстрационного примера на стороне сервера. В этой статье автор познакомит вас с простой практикой реализации прототипа простого веб-чата.
Эта статья была впервые опубликована вСообщество разработчиков RTC,можете нажать здесьПообщайтесь с автором.
В то же время к участию приглашаются небольшие партнеры, заинтересованные в аудио- и видеотехнологиях в реальном времени.👉 Конкурс эссе о пользовательском опыте Shengwang Agora SDK
Судя по демонстрационной веб-версии, выпущенной Agora, она уже имеет самые основные функции чата в реальном времени, если ее просто настроить.
Получить демо-версию веб-версии
мы основаны наОфициальная демоверсияизменить комнату чата. После загрузки веб-демо разархивируйте его, каталог выглядит следующим образом:
|---Agora_Signaling_Web
|---libs // sdk 在这里
|---samples // demo在这里
|---Agora-Signaling-Tutorial-Web // 聊天室demo
Откройте Agora-Signaling-Tutorial-Web в каталоге примеров с помощью кода Visual Studio.
|——Agora-Signaling-Tutorial-Web
|—src
| ├─assets
| │ ├─images
| │ └─stylesheets
| ├─pages
| │ ├─index
| │ └─meeting
| └─utils
|—static
|--agora.config.js // 这里配置AppId
|--AgoraSig.js // 复制它到 assets 目录
Установите зависимости и запустите демо
Кратко поговорим о sdk на веб стороне, этот sdk имеет высокую степень упаковки и даже не требует от разработчиков понимания websockt и webrtc. Просто вызовите соответствующий функциональный интерфейс.
Затем давайте вместе запустим демонстрацию.Эта демонстрация является проектом веб-пакета, и профессиональные инженеры веб-разработки не будут чувствовать себя незнакомыми.
- Сначала скопируйте AgoraSig.js в каталог astes.
- Во-вторых, установка npm
- Далее настройте appid Откройте src\static\agora.config.js, измените AGORA_APP_ID на наш собственный AppId.
- Наконец, запуск npm
В этот момент браузер должен открыть страницу (как показано ниже).
Просто введите имя пользователя, мы можем войти в чат, конечно, вы можете добавить свою собственную службу аутентификации пользователей.
Открываем две вкладки, присоединяемся к тому же p2p-каналу, что и accontA и accontB соответственно, и пытаемся отправлять сообщения друг другу.
Автор обнаружил, что наш чат не нуждается в отдельном запуске серверной части. Сторона сервера, представленная ранее, с точки зрения интерфейса, ее функция больше склонна выполнять системную трансляцию и уведомление о системных сообщениях. Поэтому, если вы хотите внедрить программное обеспечение чата с функцией резервного копирования сообщений в облаке, вы должны реализовать хранение и загрузку резервной копии на терминал.
Не будет преувеличением сказать, что этот чат может работать только с одной страницей.
Веб-версия Объяснение демо-кода
Получите веб-проект, первое, на что мы смотрим, это package.json
Мы можем видеть, от каких пакетов зависит проект, и сценарий запуска проекта.
"scripts": {
"test": "jest ./test", // 测试
"lint": "eslint .", // eslint格式化当前目录
"format": "eslint . --fix", // eslint fix当前目录下的代码格式
"dev": "cross-env NODE_ENV=development webpack-dev-server --open", // 这个会启动 webpack-dev-server 并用浏览器打开页面
"start": "npm run dev", // 功能同上一条
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules" // 编译
},
Файл конфигурации static/agora.config.js
Его нужно настроить только в следующих двух строках кода.
const AGORA_APP_ID = '6cb4f3s4c67404d4ba0ec0b' // appid
const AGORA_CERTIFICATE_ID = '' // 如果开启了token模式,这里要配置certificate_id
Статический файл SDK/AgoraSig.js
Это то же самое, что и файл sdk в каталоге lib, и его можно заменить новым sdk.
Недавно загруженная демонстрация также должна скопировать файл в каталог src/assets.
каталог утилит
Некоторые служебные классы инкапсулированы в каталоге utils.
signalingClient.js
В этом файле сигнализация SDK дополнительно инкапсулирована, некоторые действия преобразуются в обещания, а обратный вызов заменен событию.
/**
* Wrapper for Agora Signaling SDK
* Transfer some action to Promise and use Event instead of Callback
*/
import EventEmitter from 'events';
// 信令客户端类
export default class SignalingClient {
constructor(appId, appcertificate) {
this._appId = appId;
this._appcert = appcertificate;
// Init signal using signal sdk
this.signal = Signal(appId) // eslint-disable-line
// init event emitter for channel/session/call
this.channelEmitter = new EventEmitter();
this.sessionEmitter = new EventEmitter();
}
/**
* @description login agora signaling server and init 'session'
* 登录 信令服务,并初始化会话
* @description use sessionEmitter to resolve session's callback
* @param {String} account
* @param {*} token default to be omitted
* @returns {Promise}
*/
login(account, token = '_no_need_token') {
this.account = account;
return new Promise((resolve, reject) => {
this.session = this.signal.login(account, token);
// Proxy callback on session to sessionEmitter
[
'onLoginSuccess',
'onError',
'onLoginFailed',
'onLogout',
'onMessageInstantReceive',
'onInviteReceived'
].map(event => {
return (this.session[event] = (...args) => {
this.sessionEmitter.emit(event, ...args);
});
});
// Promise.then
this.sessionEmitter.once('onLoginSuccess', uid => {
this._uid = uid;
resolve(uid);
});
// Promise.catch
this.sessionEmitter.once('onLoginFailed', (...args) => {
reject(...args);
});
});
}
/**
* @description logout agora signaling server
* 退出信令服务
* @returns {Promise}
*/
logout() {
return new Promise((resolve, reject) => {
this.session.logout();
this.sessionEmitter.once('onLogout', (...args) => {
resolve(...args);
});
});
}
/**
* @description join channel
* 加入某个频道
* @description use channelEmitter to resolve channel's callback
* @param {String} channel
* @returns {Promise}
*/
join(channel) {
this._channel = channel;
return new Promise((resolve, reject) => {
if (!this.session) {
throw {
Message: '"session" must be initialized before joining channel'
};
}
this.channel = this.session.channelJoin(channel);
// Proxy callback on channel to channelEmitter
// 将回调 都代理到 对应channelEmitter
[
'onChannelJoined',
'onChannelJoinFailed',
'onChannelLeaved',
'onChannelUserJoined',
'onChannelUserLeaved',
'onChannelUserList',
'onChannelAttrUpdated',
'onMessageChannelReceive'
].map(event => {
return (this.channel[event] = (...args) => {
this.channelEmitter.emit(event, ...args);
});
});
// Promise.then
this.channelEmitter.once('onChannelJoined', (...args) => {
resolve(...args);
});
// Promise.catch
this.channelEmitter.once('onChannelJoinFailed', (...args) => {
this.channelEmitter.removeAllListeners()
reject(...args);
});
});
}
/**
* @description leave channel
* 离开当前频道
* @returns {Promise}
*/
leave() {
return new Promise((resolve, reject) => {
if (this.channel) {
this.channel.channelLeave();
this.channelEmitter.once('onChannelLeaved', (...args) => {
this.channelEmitter.removeAllListeners()
resolve(...args);
});
} else {
resolve();
}
});
}
/**
* @description send p2p message
* 发送点对点消息
* @description if you want to send an object, use JSON.stringify
* @param {String} peerAccount
* @param {String} text
*/
sendMessage(peerAccount, text) {
this.session && this.session.messageInstantSend(peerAccount, text);
}
/**
* @description broadcast message in the channel
* 发送频道消息
* @description if you want to send an object, use JSON.stringify
* 可以通过JSON.Stringify的方式发送object
* @param {String} text
*/
broadcastMessage(text) {
this.channel && this.channel.messageChannelSend(text);
}
}
pages
Вот реализация двух страниц, индексной страницы по умолчанию и страницы чата. Вы можете изменить эти две страницы с определенным пониманием webpack.
pages/index.js
Все обратите внимание, нажмите «Присоединиться к собранию», мы получим значение DOM, чей идентификатор является именем учетной записи, а затем поместите значение учетной записи в URL-адрес.
$('#join-meeting').click(function(e) {
// Join btn clicked
e.preventDefault();
var account = $('#account-name').val() || '';
if (checkAccount(account)) {
// Account has to be a non empty numeric value
window.location.href = `meeting.html?account=${account}`;
} else {
$('#account-name')
.removeClass('is-invalid')
.addClass('is-invalid');
}
});
Значение учетной записи следующей страницы чата передается через параметр учетной записи в URL-адресе.
pages/meeting.js
Класс клиента и методы класса, связанные с чатом, в основном определены в файле Meeting.js.
Во-первых, давайте посмотрим на конец файла:
// 检测获取appid 并检测是否为空
const appid = AGORA_APP_ID || '',
appcert = AGORA_CERTIFICATE_ID || '';
if (!appid) {
alert('App ID missing!');
}
//从url获取account值 ,Browser 模块事先在util/index.js中定义好的。
let localAccount = Browser.getParameterByName('account');
let signal = new SignalingClient(appid, appcert);
// Let channelName = Math.random() * 10000 + "";
// by default call btn is disabled
// 信令登陆
signal.login(localAccount).then(() => {
// Once logged in, enable the call btn
let client = new Client(signal, localAccount);
$('#localAccount').html(localAccount);
});
Далее следует сосредоточиться на клиентском классе, здесь автор только выдергивает часть кода.
Я полагаю, что многие друзья обнаружили, что аватары чата в демо-версии одинаковы, и я не вижу разницы.
На самом деле в методе формирования сообщения рендеринга можно настроить аватарку, которая по умолчанию пишется как фиксированное изображение.На самом деле можно собрать ссылку аватара согласно аккаунту.Конечно, нужно сделать интерфейс аватара пользователя самостоятельно.
buildMsg(msg, me, ts) {
let html = '';
let timeStr = this.compareByLastMoment(ts);
if (timeStr) {
html += `<div>${timeStr}</div>`;
}
let className = me ? 'message right clearfix' : 'message clearfix';
html += '<li class="' + className + '">';
// 注意看这里
html += '<img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/4/10/16a066f2aedfd60f~tplv-t2oaga2asx-image.image">';
html +=
'<div class="bubble">' +
Utils.safe_tags_replace(msg) +
'<div class="corner"></div>';
html += '<span>' + this.parseTwitterDate(ts) + '</span></div></li>';
return html;
}
Здесь следует обратить внимание на междоменные проблемы. Вам нужно самостоятельно проксировать URL-адрес интерфейса, чтобы решить проблемы междоменной безопасности. В состоянии разработки вы можете напрямую настроить прокси devServer.
Другой друг сказал, что я хочу сохранить запись сообщения, но относительно легко сохранить запись сообщения на терминале.
Обратите внимание на onReceiveMessage()
onReceiveMessage(account, msg, type) {
let client = this;
var conversations = this.chats.filter(function(item) {
return item.account === account;
});
if (conversations.length === 0) {
// No conversation yet, create one
conversations = [{ id: new Date().getTime(), account: account, type: type }];
client.chats.splice(0, 0, conversations[0]);
client.updateLocalStorage();
client.updateChatList();
}
// 可以看到下面对消息做了简单处理,然后丢到msgs中
for (let i = 0; i < conversations.length; i++) {
let conversation = conversations[i];
let msgs = this.messages[conversation.id] || [];
let msg_item = { ts: new Date(), text: msg, account: account };
msgs.push(msg_item);
this.updateMessageMap(conversation, msgs);
let chatMsgContainer = $('.chat-messages');
if (String(conversation.id) === String(this.current_conversation.id)) {
this.showMessage(this.current_conversation.id)
chatMsgContainer.scrollTop(chatMsgContainer[0].scrollHeight);
}
}
}
Возьмем ссылку на его местоположение.
Очевидно, что оба новости P2P или News Chanel, будут называть этот метод OnreceiveMessage (). Поэтому они могут реализовать их историю чата, модифицируя OnreCeiveMessage. В частности, через интерфейс для хранения нашего собственного сервера или с помощью LocalStorage, может быть лучше достигнут заканчивается запись веб-чата.
Такие какwindow.localStorage.setItem('msglog',msgs)
Поскольку его можно временно хранить в localStorage, если вы хотите экспортировать данные чата в формате json, csv не доставит хлопот.
возможные проблемы
-
ошибка установки нпм
Решение: изменить адрес склада, использовать установку пряжи, использовать vpn.
-
Может отправлять сообщения, но не может получать сообщения
Проверьте, существует ли каталог активов и статический каталог, если нет существования, скопируйте и переименуют его из каталога lib SDK для Agorasig.js
Суммировать
В целом реализовать чат на основе сигнализации Agora очень просто, судя по демо, это можно реализовать, расширив некоторые сервисы управления пользователями. Вы можете сосредоточиться на оптимизации интерактивного взаимодействия, украшении пользовательского интерфейса и сосредоточиться на сквозном бизнесе. Однако, если вам нужен больший контроль, вам нужно реализовать такие функции, как записи чата, на стороне сервера. Чтобы сделать такую функцию на основе текущей версии сигнализации, вам нужно разработать ее самостоятельно. Преимущество сигнализации в том, что удобно реализовать некоторые сценарии уведомления о сообщениях. И стыковка очень проста, если она просто упакована, ее можно встроить прямо в конец. Кроме того, для реализации экрана маркеров вы можете попробовать отправить сообщение в конце, чтобы отправить сообщение в интерфейс, который одновременно сохраняет сообщение.