Приложения обмена мгновенными сообщениями, включая сервер, управление и клиент
Он был развернут и запущен, добро пожаловать, чтобы испытать клиент и управление
Пожалуйста, не меняйте роль по умолчанию и разрешения по желанию. Пожалуйста, почувствуйте себя немного любящим и не составляйте несколько нецивилизованных имен.
Использование структуры яиц, на стороне сервера IM Service
После разработки мобильного Интернета услуги обмена мгновенными сообщениями, возглавляемые WeChat, были интегрированы в каждый угол нашей жизни, а также играют важную роль в некоторых бизнесах компании. Наша компания использовала услуги обмена мгновенными сообщениями, но многие индивидуальные потребности не могут быть достигнуты. Поэтому было решено разработать микросервис мгновенного обмена сообщениями, который удовлетворяет индивидуальным потребностям внутри.
Структура socket.io Прочитав несколько примеров, я подумал, что это действительно удобно использовать и поддерживать на всей платформе. Таким образом, этот микросервис был реализован в команде фронта, и в настоящее время эффект довольно хорош.
В настоящее время сообщество имеет менее или слишком простой контент в этой области (есть только одна публичная чата). Кроме того, очень неудобно быть PM в процессе развития бизнеса, поэтому я хочу отказаться от некоторых уникальных вещей и реализовать простое и полное приложение IM, которое не смешивает бизнес компании с простыми функциями, включая сервер, управление и клиент. Объектом имитации клиента является WeChat, потому что я очень знаком с ним и не должен слишком много думать о продукте. Кроме того, люди, которые пробуют его, очень хорошо знакомы с этим и не требуют слишком больших затрат на общение.
Для разработки полного набора услуг обмена мгновенными сообщениями требуются следующие детали:
Родился для фреймворков и приложений на уровне предприятия
Причина, по которой я выбрал рамку Alibaba's Egg.js в качестве поддержки, заключается в том, что они проделали хорошую работу в масштабной реализации и безопасности в нем. Причина, по которой они не выбрали гнездо, заключается в том, что интегрировать socket.io трудно. ORM использует продолжение, а база данных - MySQL. Я использовал его раньше, так что это менее сложно начать.
Из-за коробки фронтального/дизайнерского решения
Причиной выбора Ant Design Pro является то, что я знаком с ведром семьи Vue. Я хочу воспользоваться этой возможностью, чтобы познакомиться с процессом разработки всей экосистемы React и почувствовать важные различия и различные пути двух основных рамок развития в Китае. Ant Design Pro был выпущен в течение нескольких лет, и он действительно принесла повышение эффективности для малых и средних предприятий, что прямо для моих потребностей.
Стандартные инструменты, разработанные Vue.js
Используйте @vue/cli для создания клиента IM Service, мобильного проекта H5 и Framework пользовательского интерфейса Youzan Vant, который объединяет мой компонент с открытым исходным кодом Vue-Page-Stack и лучшую прокрутку г-на Хуанга, чтобы реализовать основные функции IM
Как фронт-инженер, большинство ежедневных задач не требуют размышлений об отношениях сущности. Однако, основываясь на моем реальном опыте, понимание отношений сущности может помочь нам лучше понять бизнес -модели. Улучшение продукта и понимания бизнеса очень помогает нам. Мы можем найти много нелогичных аспектов во время рассмотрения спроса (почему мы должны снова жаловаться на менеджера по продукту). Если мы сможем предложить это в настоящее время, мы возьмем инициативу, чтобы избежать повторного развития в последующем процессе, и в то же время мы можем сформировать относительно хорошее взаимодействие со студентами на стороне продукта (а не конфронтация). Вот некоторые из наиболее важных отношений сущности:
Из приведенного выше рисунка мы видим, что пользователь является ядром всей диаграммы взаимосвязи. Ниже приводится связь между различными сущностями:
Ниже приведено подробное введение в сеансы, роли и разрешения:
При завершении приложения об обмене мгновенным сообщением первое, что вам нужно рассмотреть, это разговор, который является окном разговора в нашем WeChat. Требуется много усилий, чтобы подумать о отношениях между разговорами и сообщениями, пользователями и группами, и, наконец, сформировать следующие базовые отношения:
Другими словами, пользователь не имеет прямых отношений с сеансом и может получить сеанс только через соответствующий отдельный чат и групповой чат пользователя. Это может иметь следующие преимущества:
Чтобы разработать гибкую, универсальную и удобную систему управления разрешениями, эта система использует контроль RBAC (контроль доступа на основе ролей) для разработки общей платформы «разрешения пользователя» для удобства более позднего расширения.
RBAC (контроль доступа на основе ролей) относится к тому, что пользователь ассоциируется с разрешениями через роли. То есть у пользователя есть несколько ролей, и у каждой роли есть несколько разрешений (конечно, не объединяют противоречивые роли и разрешения вместе). Таким образом, построена модель авторизации «Пользовательских промежутков». В этой модели, как правило, существует взаимосвязь между пользователями и ролями, а также между ролями и разрешениями.
Эта система имеет роли администратора, общего пользователя, запрещенного пользователя и запрещенного пользователя, и различные разрешения присваиваются различным ролям. Следовательно, необходимо выполнить обработку единой аутентификации (посредством промежуточного программного обеспечения) для маршрутизации интерфейса, такой как управление и речь. Конкретные методы и методы будут подробно объяснены в заднем проекте. Эта система временно использует метод предопределенных ролей и разрешений. Если вы хотите расширить в будущем, вы можете редактировать роли и разрешения.
Я никогда не видел управленческой стороны WeChat, но вы можете себе представить, что администраторы могут настроить роли и разрешения пользователя и редактировать статус группы:
После регистрации и входа в систему вы можете добавить друзей и нормально объединять группы, изменить личную базовую информацию и приложения процесса.
Невозможно войти в систему
Например: теперь появилась новая версия личного центра, которую необходимо проверить в Интернете. Сначала создайте новую роль «Тест личный центр», а затем назначите соответствующие разрешения на роль; Затем группируйте обычных пользователей и выберите некоторых людей для настройки этой роли, чтобы вы могли ее проверить.
Давайте поговорим о основном принципе общения мгновенных услуг обмена сообщениями. Как и General HTTP Services, есть сервер и клиент для общения, но подробный протокол и методы обработки разные.
По историческим причинам основной протокол HTTP в настоящее время является протоколом без сохранения состояния (HTTP2 не широко используется в настоящее время). Как правило, клиент активно инициирует запрос, а затем отвечает на него. Таким образом, чтобы понять, что сервер нажимает информацию клиенту, фронт должен активно опрашиваться на задний план. Этот метод неэффективен и подвержен ошибке. Это действительно делается на нашей домашней странице управления (5S один раз).
Чтобы удовлетворить эту потребность в серверной стороне, чтобы активно выдвигать информацию, HTML5 начал предоставлять протокол для полномулуплексного общения на одном соединении TCP, а именно WebSocket. WebSocket упрощает обмен данными между клиентами и серверами, позволяя серверу активно разжигать данные клиентам. Протокол WebSocket родился в 2008 году и стал международным стандартом в 2011 году. В настоящее время большинство браузеров уже поддерживали его.
Использование WebSocket довольно просто:
var ws = new WebSocket("wss://echo.websocket.org");
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
ws.onclose = function(evt) {
console.log("Connection closed.");
};
С помощью протокола WebSocket у сервера есть расширенное оружие для активного продвижения информации. Так есть ли способ быть совместимым со старыми и новыми браузерами? На самом деле, многие думают об этом, и ответ - socket.io
socket.io socket.io далее инкапсулирует интерфейс WebSocket и может автоматически переключаться на использование опроса в старых браузерах для общения (наши пользователи не воспринимают), образуя унифицированный набор интерфейсов, значительно снижая бремя разработки. В основном у него есть следующие преимущества:
Это домашняя страница сокета.io
Самый быстрый и надежный двигатель обмена мгновенными сообщениями (с самым быстрым и наиболее надежным двигателем в реальном времени)
Это действительно легко использовать:
var io = require('socket.io')(80);
var cfg = require('./config.json');
var tw = require('node-tweet-stream')(cfg);
tw.track('socket.io');
tw.track('javascript');
tw.on('tweet', function(tweet){
io.emit('tweet', tweet);
});
Давайте сосредоточимся на нескольких важных моментах проекта на стороне сервера. Большая часть контента необходимо просмотреть на официальном сайте яиц.
Используйте строительные леса npm init egg --type=simple для инициализации сервера проекта, установки MySQL (My IS версия 8.0), настроить пароль ссылки базы данных, необходимый для продолжения проникновения и т. Д., И вы можете его запустить
// 目录结构说明
├── package.json // 项目信息
├── app.js // 启动文件,其中有一些钩子函数
├── app
| ├── router.js // 路由
│ ├── controller
│ ├── service
│ ├── middleware // 中间件
│ ├── model // 实体模型
│ └── io // socket.io 相关
│ ├── controller
│ └── middleware // io独有的中间件
├── config // 配置文件
| ├── plugin.js // 插件配置文件
| └── config.default.js // 默认的配置文件
├── logs // server运行期间产生的log文件
└── public // 静态文件和上传文件目录
Маршрутизатор в основном используется для описания соответствия между URL -адресом запроса и контроллером, который специально предпринимает действие выполнения, то есть app/router
app/middleware/auth.jsapp/middleware/admin.js Поскольку эта система имеет разные роли в качестве администраторов и общих пользователей связи, для маршрутизации интерфейса и коммуникации требуется единая обработка аутентификации.
Например, маршрут со стороны управления /v1/admin/... , я хочу добавить аутентификацию администратора ко всем маршрутам этой серии. В настоящее время вы можете использовать промежуточное программное обеспечение для аутентификации. Ниже приведен конкретный пример использования промежуточного программного обеспечения в административном маршрутизаторе.
// middware
module.exports = () => {
return async function admin(ctx, next) {
let { session } = ctx;
// 判断admin权限
if (session.user && session.user.rights.some(right => right.keyName === 'admin')) {
await next();
} else {
ctx.redirect('/login');
}
};
};
// router
const admin = app.middleware.admin();
router.get('/api/v1/admin/rights', admin, controller.v1.admin.rightsIndex);
Используемая комбинация Scentize+MySQL, а Egg также имеет продолжение связанных плагинов. Scielize - это ORM, используемый в среде узлов, поддерживающий Postgres, MySQL, MariaDB, SQLite и Microsoft SQL Server, который довольно удобен в использовании. Вы должны сначала определить прямую связь между моделью и моделью. После установки отношений вы можете использовать некоторые заданные методы.
Основная информация модели легче обрабатывать. На что нужно обратить внимание, так это дизайн отношений между организациями, то есть ассоциированным. Ниже приведено описание отношений пользователя
// User.js
module.exports = app => {
const { STRING } = app.Sequelize;
const User = app.model.define('user', {
provider: {
type: STRING
},
username: {
type: STRING,
unique: 'username'
},
password: {
type: STRING
}
});
User.associate = function() {
// One-To-One associations
app.model.User.hasOne(app.model.UserInfo);
// One-To-Many associations
app.model.User.hasMany(app.model.Apply);
// Many-To-Many associations
app.model.User.belongsToMany(app.model.Group, { through: 'user_group' });
app.model.User.belongsToMany(app.model.Role, { through: 'user_role' });
};
return User;
};
Например, взаимосвязь между пользователем и пользователем INFO-это отношения один к одному. После того, как это определено, мы можем использовать user.setUserInfo(userInfo) при создании нового пользователя. Если вы хотите получить основную информацию этого пользователя, вы также можете использовать user.getUserInfo()
Отношения между пользователем и применением-один-один, то есть пользователь может соответствовать нескольким приложениям, и в настоящее время применяются только друзья и групповые приложения:
При добавлении приложения вы можете использовать user.addApply(apply) , а при его получении вы можете использовать его следующим образом:
const result = await ctx.model.Apply.findAndCountAll({
where: {
userId: ctx.session.user.id,
hasHandled: false
}
});
Отношения между пользователем и группой являются много-ко многим, то есть пользователь может соответствовать нескольким группам, а группа может соответствовать нескольким пользователям. Таким образом, Scielize установит промежуточную таблицу user_group для достижения этой связи.
Я обычно использую это:
group.addUser(user); // 建立群组和用户的关系
user.getGroups(); // 获取用户的群组信息
Яйцо обеспечивает плагин с яйцом .IO. Вам нужно открыть плагин в config/plugin.js после установки Egg-socket.io. У IO есть собственное промежуточное программное обеспечение и контроллер.
Маршрут IO отличается от маршрута HTTP -запросов. Обратите внимание, что маршрут здесь не может быть обработан с помощью промежуточного программного обеспечения (я не добился успеха), поэтому я обработал обработку запрета в контроллере.
// 加入群
io.of('/').route('/v1/im/join', app.io.controller.im.join);
// 发送消息
io.of('/').route('/v1/im/new-message', app.io.controller.im.newMessage);
// 查询消息
io.of('/').route('/v1/im/get-messages', app.io.controller.im.getMessages);
Примечание: я рассматриваю отношения как группы, так и друга как комнату (то есть сеанс), чтобы я мог отправлять сообщения непосредственно в Romm, и все внутри могут их получить.
Существует два промежуточного программного обеспечения по умолчанию, одним из них является промежуточное программное обеспечение подключения при подключении и отключении, которое используется для проверки состояния входа и процесса бизнес -логики; Другое - это промежуточное программное обеспечение для пакетов, называемое каждый раз, когда отправляется сообщение, которое используется для печати журнала
Поскольку разрешение вызова предусмотрено, оно обрабатывается в контроллере
// 对用户发言的权限进行判断
if (!ctx.session.user.rights.some(right => right.keyName === 'speak')) {
return;
}
Чаты делятся на отдельные чаты и групповые чаты. Информация о чате временно включает в себя общий текст, изображения, видео и сообщения о позиционировании, которые можно расширить на заказы или продукты в соответствии с бизнесом.
Структивный дизайн сообщения относится к проектированию нескольких сторонних услуг, а также была скорректирована в сочетании с ситуацией самого этого проекта. Это может быть расширен по желанию, и сделано следующее объяснение:
const Message = app.model.define('message', {
/**
* 消息类型:
* 0:单聊
* 1:群聊
*/
type: {
type: STRING
},
// 消息体
body: {
type: JSON
},
fromId: { type: INTEGER },
toId: { type: INTEGER }
});
Тело хранит тело сообщения, которое используется для хранения разных форматов сообщений, используя JSON:
// 文本消息
{
"type": "txt",
"msg":"哈哈哈" //消息内容
}
// 图片消息
{
"type": "img",
"url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
"ext":"jpg",
"w":360, //宽
"h":480, //高
"size": 388245
}
// 视频消息
{
"type": 'video',
"url": "http://nimtest.nos.netease.com/cbc500e8-e19c-4b0f-834b-c32d4dc1075e",
"ext":"mp4",
"w":360, //宽
"h":480, //高
"size": 388245
}
// 地理位置消息
{
"type": "loc",
"title":"中国 浙江省 杭州市 网商路 599号", //地理位置title
"lng":120.1908686708565, // 经度
"lat":30.18704515647036 // 纬度
}
В настоящее время есть только один, который должен обновить знак Baidu. Здесь довольно просто, просто обратитесь к официальной документации.
Интеллектуальная настройка диалога и платформу обслуживания
Это довольно интересно. Вы можете создать нового робота и добавить соответствующие навыки по адресу https://ai.baidu.com/ . Я болтаю здесь, и есть интеллектуальные вопросы и с и т. Д.
Если вы не хотите начинать, вы можете удалить ctx.service.baidu.getToken();
Прежде всего, вам нужно настроить его в файле конфигурации. Я ограничил размер файла здесь и формат видеофайла с перекрестным iOS:
config.multipart = {
mode: 'file',
fileSize: '3mb',
fileExtensions: ['.mov']
};
Унифицированный интерфейс используется для обработки загрузки файлов. Основной проблемой является написание файлов, а файлы - это список файлов, передаваемый с передней части
for (const file of ctx.request.files) {
// 生成文件路径,注意upload文件路径需要存在
const filePath = `./public/upload/${
Date.now() + Math.floor(Math.random() * 100000).toString() + '.' + file.filename.split('.').pop()
}`;
const reader = fs.createReadStream(file.filepath); // 创建可读流
const upStream = fs.createWriteStream(filePath); // 创建可写流
reader.pipe(upStream); // 可读流通过管道写入可写流
data.push({
url: filePath.slice(1)
});
}
Я сохраняю /public/upload/ в каталоге сервера. Этот каталог требует конфигурации статического файла:
config.static = {
prefix: '/public/',
dir: path.join(appInfo.baseDir, 'public')
};
Официальный документ из яиц этой главы - убить вас, нет ничего примеров, вы должны прочитать исходный код. Это так ужасно. Я давно изучал его, прежде чем выяснить, что происходит.
Поскольку я хочу более свободно управлять паролем учетной записи, я не использую паспорт для регистрации пароля учетной записи, но использую обычную аутентификацию и сеанс обычного интерфейса.
Ниже приведено подробное описание процесса входа в систему с использованием сторонней платформы (я выбрал GitHub):
Откройте плагин:
// config/plugin.js
module.exports.passport = {
enable: true,
package: 'egg-passport',
};
module.exports.passportGithub = {
enable: true,
package: 'egg-passport-github',
};
// config.default.js
config.passportGithub = {
key: 'your_clientID',
secret: 'your_clientSecret',
callbackURL: 'http://localhost:3000/api/v1/passport/github/callback' // 注意这里非常的关键,这里需要和你在github上面设置的Authorization callback URL一致
};
this.app.passport.verify(verify);
const github = app.passport.authenticate('github', { successRedirect: '/' }); // successRedirect就是最后校验完毕后前端会跳转的路由,我这里直接跳转到主页了
router.get('/v1/passport/github', github);
router.get('/v1/passport/github/callback', github);
/v1/passport/github на передней части и инициируйте авторизацию Github для этого приложения. После успеха GitHub перейдет на http://localhost:3000/v1/passport/github/callback?code=12313123123 . Наш плагин GithubPassport получит информацию пользователя о GitHub. После получения подробной информации нам необходимо проверить пользовательскую информацию в app/passport/verify.js и связать ее с информацией пользователя нашей собственной платформы, а также присвойте значение сеансу // verify.js
module.exports = async (ctx, githubUser) => {
const { service } = ctx;
const { provider, name, photo, displayName } = githubUser;
ctx.logger.info('githubUser', { provider, name, photo, displayName });
let user = await ctx.model.User.findOne({
where: {
username: name
}
});
if (!user) {
user = await ctx.model.User.create({
provider,
username: name
});
const userInfo = await ctx.model.UserInfo.create({
nickname: displayName,
photo
});
const role = await ctx.model.Role.findOne({
where: {
keyName: 'user'
}
});
user.setUserInfo(userInfo);
user.addRole(role);
await user.save();
}
const { rights, roles } = await service.user.getUserAttribute(user.id);
// 权限判断
if (!rights.some(item => item.keyName === 'login')) {
ctx.body = {
statusCode: '1',
errorMessage: '不具备登录权限'
};
return;
}
ctx.session.user = {
id: user.id,
roles,
rights
};
return githubUser;
};
Обратите внимание на приведенный выше код. Если это первая авторизация, пользователь будет создан. Если это второе разрешение, пользователь был создан.
Когда система развернута или запущена, необходимо предварительно установлено некоторые данные и таблицы, а коды находятся в app.js и app/service/startup.js
Логика заключается в том, что после начала проекта используйте модель для синхронизации структуры таблицы в базе данных, а затем начните создавать некоторые основные данные:
После завершения вышеизложенного, начальные данные были заполнены и могут работать нормально
Я купил сервер Centos в Tencent Cloud, доменное имя, которое я купил в Alibaba Cloud, установлен узл (12.18.2), Nginx и Mysql8.0 и начал непосредственно на Centos. Фронт-энд использует Nginx для обратного прокси. Из -за ограниченных ресурсов сервера нет инструментов автоматизации Jenkins и Docker, что приводит к некоторым ручным операциям при обновлении.