即时通讯源码是一个完整的消息传递套件,供企业构建跨 Web、Android、iOS 设备的可定制协作平台,以建立虚拟连接。即时通讯解决方案提供多种通信媒介,如语音和视频通话、实时聊天、视频会议,以连接来自多个设备的远程团队。即时通讯源码提供功能丰富的 API 和 SDK,以在任何应用程序上集成通信平台。企业消息传递解决方案能够拥有大约 1M+ 的并发用户群。即时通讯源码兼容端到端加密、信号协议、AES-256 位和其他隐私合规性,如 HIPAA、GDPR、COPAA,以保护整个对话。
演示:im.jstxym.top
技术栈:
MongoDB
Express
React
Node
除了上述技术之外,我还使用TypeScript来提高我的代码的健壮性,并使用Redux来管理应用程序状态。
我还应该提到socket.io,它支持浏览器和服务器之间的实时、双向和基于事件的通信。
对于部署,一种简单有效的方法是将前端托管在Netlify上,后端托管在云平台上。
以下是我通常用来增强编程体验的工具列表:
操作系统:MacOS
终端:iterm2
IDE:VSCode
版本控制:Git
包管理器:NPM
项目组织:Notion
线框和设计
老实说,我对设计产品的 UI 并没有太多的乐趣。因此,我决定使用现有的线框并专注于代码。
快速概览:
数据建模和 API 路由
数据库设计和 API 路由是重要的步骤。在开始编码之前确保你有一个行动计划,否则这将是一场灾难
这是一个使用Lucidchart制作的简单数据模型:
确实很简单,但是对于这个项目来说已经足够了。
正如您可能猜到的,我们正在使用 Node/Express 构建一个涉及 HTTP 请求的 REST API。
即时通讯源码项目组织
步骤 01:设置和前端
开始编码总是那么令人兴奋,这是我最喜欢的过程。我从设置前端和后端开始,这意味着安装依赖项、环境变量、CSS 重置、创建数据库......设置完成后,我构建了应该出现在屏幕上的每一个组件,并确保它们对移动设备友好。
说到组件和 UI,这里有一个简单的例子:
// TopBar/index.tsximport React from 'react';import { IconButton } from '@material-ui/core';import MenuIcon from '@material-ui/icons/Menu';// Local Importsimport styles from './styles.module.scss';type Props = { title?: String; menuClick: () => void;};const TopBar: React.FC = props => { return ( {props.title}
);};export default TopBar;// TopBar/styles.module.scss.container { width: 100%; height: 60px; box-shadow: 0px 4px 4px rgba($color: #000, $alpha: 0.2); display: flex; align-items: center; justify-content: center;}.wrapper { width: 95%; display: flex; align-items: center;}.title { font-size: 18px;}.iconButton { display: none !important; @media (max-width: 767px) { display: inline-block !important; }}.menu { color: #e0e0e0;}
没什么特别的,它是TypeScript和SCSS模块的基本实现。我非常喜欢SCSS,并为所有感兴趣的人写了一个介绍:您还可以注意到,一些组件(图标、输入等)是从我最喜欢的 UI 库中导入的:Material UI。说到TypeScript,最初的日子真的很痛苦和累,但到最后,在开发过程中发现 bug 似乎非常容易。
我使用的另一个很酷的工具是Formik,它以一种智能且简单的方式管理表单验证。
// Login/index.tsximport React, { useState } from 'react';import { Link } from 'react-router-dom';import axios from 'axios';import { TextField, FormControlLabel, Checkbox, Snackbar, CircularProgress } from '@material-ui/core';import MuiAlert from '@material-ui/lab/Alert';import { useDispatch } from 'react-redux';import { useFormik } from 'formik';import * as Yup from 'yup';import { useHistory } from 'react-router-dom';// Local Importsimport logo from '../../../assets/gc-logo-symbol-nobg.png';import CustomButton from '../../Shared/CustomButton/index';import styles from './styles.module.scss';type Props = {};type SnackData = { open: boolean; message: string | null;};const Login: React.FC = props => { const dispatch = useDispatch(); const history = useHistory(); const [isLoading, setIsLoading] = useState(false); const [checked, setChecked] = useState(false); const [snack, setSnack] = useState({ open: false, message: null }); // Async Requests const loginSubmit = async (checked: boolean, email: string, password: string) => { setIsLoading(true); let response; try { response = await axios.post(`${process.env.REACT_APP_SERVER_URL}/users/login`, { checked, email: email.toLowerCase(), password: password.toLowerCase() }); } catch (error) { console.log('[ERROR][AUTH][LOGIN]: ', error); setIsLoading(false); return; } if (!response.data.access) { setSnack({ open: true, message: response.data.message }); setIsLoading(false); return; } if (checked) { localStorage.setItem('userData', JSON.stringify({ id: response.data.user.id, token: response.data.user.token })); } dispatch({ type: 'LOGIN', payload: { ...response.data.user } }); history.push(''); setIsLoading(false); }; const formik = useFormik({ initialValues: { email: '', password: '' }, validationSchema: Yup.object({ email: Yup.string().email('Invalid email address').required('Required'), password: Yup.string() .min(6, 'Must be 6 characters at least') .required('Required') .max(20, 'Can not exceed 20 characters') }), onSubmit: values => loginSubmit(checked, values.email, values.password) }); return ( Don't have an account? Sign Up
{isLoading && } setSnack({ open: false, message: null })} autoHideDuration={5000}> setSnack({ open: false, message: null })} severity="error"> {snack.message} );};export default Login;
步骤 02:后端
服务器非常简单,它是 Node/Express 服务器经典样式。然后,我注册了路由并连接了相应的控制器。在我的控制器中,您可以找到经典的 CRUD 操作和一些自定义函数。多亏了JWT,才有可能在安全方面工作,这对我来说很重要。现在是这个应用程序最酷的功能,双向通信,或者我应该说socket.io吗?
这是一个例子:
// app.js - Server side// Establish a connectionio.on('connection', socket => { // New user socket.on('new user', uid => { userList.push(new User(uid, socket.id)); }); // Join group socket.on('join group', (uid, gid) => { for (let i = 0; i < userList.length; i++) { if (socket.id === userList[i].sid) userList[i].gid = gid; } }); // New group socket.on('create group', (uid, title) => { io.emit('fetch group'); }); // New message socket.on('message', (uid, gid) => { for (const user of userList) { if (gid === user.gid) io.to(user.sid).emit('fetch messages', gid); } }); // Close connection socket.on('disconnect', () => { for (let i = 0; i < userList.length; i++) { if (socket.id === userList[i].sid) userList.splice(i, 1); } });});// AppView/index.tsx - Client side useEffect(() => { const socket = socketIOClient(process.env.REACT_APP_SOCKET_URL!, { transports: ['websocket'] }); socket.emit('new user', userData.id); socket.on('fetch messages', (id: string) => fetchMessages(id)); socket.on('fetch group', fetchGroups); setSocket(socket); fetchGroups(); }, []);
我发现了express-validator,它在服务器端提供输入验证很有帮助。毫无疑问,我将再次使用。
步骤 03:修复和部署
好的,该应用程序看起来不错,功能运行良好。是时候完成这个投资组合项目并开始一个新的项目了。我不是云解决方案和复杂 CI/CD 方法的专家,所以我会满足于免费的托管服务。云平台有一个适用于后端的免费解决方案。我的节点服务器上传 5 分钟后,它独立运行。我在客户端遇到了一些安全问题。
最后,用户上传的图像通过他们的公共 API存储在我的云帐户中。
即时通讯源码特征:
视频通话
语音通话
实时消息
现场直播
视频会议
SIP 和 VoIP 通话
一键通
屏幕共享
多通道
端到端加密
自定义身份验证
以访客身份登录
随机头像/个人资料图片上传
授权(json web 令牌)
端到端输入验证
创建和加入频道
即时消息
结论
我非常享受在这个项目上的工作并学到了很多东西。很高兴与您分享这个过程,我迫不及待地想听到您的提示和反馈。这个项目无非是一个组合项目,代码开源的,您可以随意使用它。
来源地址:https://blog.csdn.net/ityuanh/article/details/127388905