commit
7311f1ed36
@ -0,0 +1,24 @@ |
||||
# Logs |
||||
logs |
||||
*.log |
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
||||
pnpm-debug.log* |
||||
lerna-debug.log* |
||||
|
||||
node_modules |
||||
dist |
||||
dist-ssr |
||||
*.local |
||||
|
||||
# Editor directories and files |
||||
.vscode/* |
||||
!.vscode/extensions.json |
||||
.idea |
||||
.DS_Store |
||||
*.suo |
||||
*.ntvs* |
||||
*.njsproj |
||||
*.sln |
||||
*.sw? |
@ -0,0 +1,20 @@ |
||||
module.exports = { |
||||
root: true, |
||||
env: { browser: true, es2020: true }, |
||||
extends: [ |
||||
'eslint:recommended', |
||||
'plugin:react/recommended', |
||||
'plugin:react/jsx-runtime', |
||||
'plugin:react-hooks/recommended', |
||||
], |
||||
ignorePatterns: ['dist', '.eslintrc.cjs'], |
||||
parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, |
||||
settings: { react: { version: '18.2' } }, |
||||
plugins: ['react-refresh'], |
||||
rules: { |
||||
'react-refresh/only-export-components': [ |
||||
'warn', |
||||
{ allowConstantExport: true }, |
||||
], |
||||
}, |
||||
} |
@ -0,0 +1,24 @@ |
||||
# Logs |
||||
logs |
||||
*.log |
||||
npm-debug.log* |
||||
yarn-debug.log* |
||||
yarn-error.log* |
||||
pnpm-debug.log* |
||||
lerna-debug.log* |
||||
|
||||
node_modules |
||||
dist |
||||
dist-ssr |
||||
*.local |
||||
|
||||
# Editor directories and files |
||||
.vscode/* |
||||
!.vscode/extensions.json |
||||
.idea |
||||
.DS_Store |
||||
*.suo |
||||
*.ntvs* |
||||
*.njsproj |
||||
*.sln |
||||
*.sw? |
@ -0,0 +1,8 @@ |
||||
# React + Vite |
||||
|
||||
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. |
||||
|
||||
Currently, two official plugins are available: |
||||
|
||||
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh |
||||
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh |
@ -0,0 +1,13 @@ |
||||
<!doctype html> |
||||
<html lang="zh"> |
||||
<head> |
||||
<meta charset="UTF-8" /> |
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" /> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
||||
<title>实时通信</title> |
||||
</head> |
||||
<body> |
||||
<div id="root"></div> |
||||
<script type="module" src="/src/main.jsx"></script> |
||||
</body> |
||||
</html> |
@ -0,0 +1,29 @@ |
||||
{ |
||||
"name": "client", |
||||
"private": true, |
||||
"version": "0.0.0", |
||||
"type": "module", |
||||
"scripts": { |
||||
"dev": "vite", |
||||
"build": "vite build", |
||||
"lint": "eslint client --ext js,jsx --report-unused-disable-directives --max-warnings 0", |
||||
"preview": "vite preview" |
||||
}, |
||||
"dependencies": { |
||||
"localforage": "^1.10.0", |
||||
"react": "^18.2.0", |
||||
"react-dom": "^18.2.0", |
||||
"react-router-dom": "^6.15.0", |
||||
"sass": "^1.66.1" |
||||
}, |
||||
"devDependencies": { |
||||
"@types/react": "^18.2.15", |
||||
"@types/react-dom": "^18.2.7", |
||||
"@vitejs/plugin-react": "^4.0.3", |
||||
"eslint": "^8.45.0", |
||||
"eslint-plugin-react": "^7.32.2", |
||||
"eslint-plugin-react-hooks": "^4.6.0", |
||||
"eslint-plugin-react-refresh": "^0.4.3", |
||||
"vite": "^4.4.5" |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 1.5 KiB |
@ -0,0 +1,11 @@ |
||||
import { useState } from 'react' |
||||
import {useRoutes} from "react-router-dom"; |
||||
import {routerList} from "./route/index.jsx"; |
||||
|
||||
function App() { |
||||
const [count, setCount] = useState(0) |
||||
|
||||
return useRoutes(routerList) |
||||
} |
||||
|
||||
export default App |
@ -0,0 +1,22 @@ |
||||
html,body,#root{ |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
margin: 0; |
||||
padding: 0; |
||||
} |
||||
#root{ |
||||
display: flex; |
||||
overflow: hidden; |
||||
& > div{ |
||||
position: relative; |
||||
overflow: hidden; |
||||
} |
||||
& > div:first-child{ |
||||
flex-shrink: 0; |
||||
width: 240px; |
||||
} |
||||
& > div:last-child{ |
||||
flex: 1; |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
import React from 'react' |
||||
import ReactDOM from 'react-dom/client' |
||||
import { BrowserRouter } from 'react-router-dom' |
||||
import App from "./App.jsx"; |
||||
import './assets/index.scss' |
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render( |
||||
<React.StrictMode> |
||||
<BrowserRouter> |
||||
<App/> |
||||
</BrowserRouter> |
||||
</React.StrictMode>, |
||||
) |
@ -0,0 +1,37 @@ |
||||
// | ------------------------------------------------------------ |
||||
// | @版本: version 0.1 |
||||
// | @创建人: 【Nie-x7129】 |
||||
// | @E-mail: x71291@outlook.com |
||||
// | @文件描述: index.jsx | 路由表 |
||||
// | @创建时间: 2023-08-30 15:43 |
||||
// | @更新时间: 2023-08-30 15:43 |
||||
// | @修改记录: |
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*- |
||||
// | = |
||||
// | ------------------------------------------------------------ |
||||
|
||||
import { Navigate } from 'react-router-dom' |
||||
import Home from "../views/Home/index.jsx"; |
||||
import Signin from "../views/Signin/index.jsx"; |
||||
import WebSocketClient from "../views/WebSocket/index.jsx"; |
||||
|
||||
export const routerList = [ |
||||
{ |
||||
path:'/', |
||||
element: <Navigate to = '/signin'/> |
||||
}, |
||||
{ |
||||
path:'/signin', |
||||
element: <Signin/> |
||||
}, |
||||
{ |
||||
path:'/home', |
||||
element: <Home/>, |
||||
children:[ |
||||
{ |
||||
path:'websocket', |
||||
element: <WebSocketClient/> |
||||
}, |
||||
] |
||||
}, |
||||
] |
@ -0,0 +1,45 @@ |
||||
// | ------------------------------------------------------------ |
||||
// | @版本: version 0.1 |
||||
// | @创建人: 【Nie-x7129】 |
||||
// | @E-mail: x71291@outlook.com |
||||
// | @文件描述: Home.jsx | |
||||
// | @创建时间: 2023-08-30 15:52 |
||||
// | @更新时间: 2023-08-30 15:52 |
||||
// | @修改记录: |
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*- |
||||
// | = |
||||
// | ------------------------------------------------------------ |
||||
|
||||
import {Outlet, NavLink, useLocation} from "react-router-dom"; |
||||
import css from './index.module.scss' |
||||
import {useEffect, useState} from "react"; |
||||
|
||||
export default function Home(){ |
||||
// @ host - String - 描述:ws链接地址 |
||||
const [host, setHost] = useState(''); |
||||
// @ nickname - String - 描述:ws昵称 |
||||
const [nickname, setNickName] = useState(''); |
||||
// @ location - String - 描述:当前路由信息 |
||||
const [location, setLocation] = useState(useLocation()); |
||||
useEffect(() => { |
||||
setHost(window.localStorage.getItem('wsHost')); |
||||
setNickName(window.localStorage.getItem('wsNickname')) |
||||
}, [0]); |
||||
return <> |
||||
<div className={css.left}> |
||||
<div className={css.info}> |
||||
<header>个人信息</header> |
||||
<div>昵称: {nickname}</div> |
||||
<div>链接地址: {host}</div> |
||||
</div> |
||||
<div className={css.server}> |
||||
<header>服务</header> |
||||
<NavLink to={'websocket'} className={({ isActive }) => isActive ? css.choose : ''}>WebSocket</NavLink> |
||||
</div> |
||||
</div> |
||||
<div className={css.right}> |
||||
<header>{location?.pathname && location?.pathname?.split('/').slice(-1).toString().toUpperCase()}</header> |
||||
<div><Outlet/></div> |
||||
</div> |
||||
</> |
||||
} |
@ -0,0 +1,76 @@ |
||||
.left{ |
||||
position: relative; |
||||
overflow: hidden; |
||||
height: 100%; |
||||
display: flex; |
||||
flex-direction: column; |
||||
box-sizing: border-box; |
||||
padding: 10px; |
||||
& > div.info{ |
||||
position: relative; |
||||
flex-shrink: 0; |
||||
overflow: hidden; |
||||
border-radius: 10px; |
||||
background: #00033322; |
||||
box-sizing: border-box; |
||||
padding: 10px; |
||||
&>header{ |
||||
position: relative; |
||||
line-height: 3em; |
||||
text-align: center; |
||||
font-size: 18px; |
||||
} |
||||
& > div{ |
||||
position: relative; |
||||
line-height: 2em; |
||||
font-size: 14px; |
||||
} |
||||
} |
||||
& > div.server{ |
||||
position: relative; |
||||
flex: 1; |
||||
overflow: hidden; |
||||
background: aquamarine; |
||||
margin-top: 10px; |
||||
border-radius: 10px; |
||||
padding: 10px; |
||||
&>header{ |
||||
position: relative; |
||||
line-height: 3em; |
||||
text-align: center; |
||||
font-size: 18px; |
||||
} |
||||
} |
||||
|
||||
|
||||
.choose{ |
||||
all: unset; |
||||
cursor: pointer; |
||||
background: darkmagenta; |
||||
color: #fefefe; |
||||
} |
||||
} |
||||
|
||||
.right{ |
||||
position: relative; |
||||
overflow: hidden; |
||||
height: 100%; |
||||
padding: 10px; |
||||
box-sizing: border-box; |
||||
margin: 10px 10px 10px 0; |
||||
border-radius: 10px; |
||||
background: #eeeeee99; |
||||
display: flex; |
||||
flex-direction: column; |
||||
& > header{ |
||||
position: relative; |
||||
flex-shrink: 0; |
||||
line-height: 3em; |
||||
font-size: 18px; |
||||
font-weight: bold; |
||||
} |
||||
& > div{ |
||||
position: relative; |
||||
flex: 1; |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
import css from './index.module.scss' |
||||
import {useEffect, useState} from "react"; |
||||
export default function MessageWindow(props){ |
||||
// @ inputMessage - String - 描述:输入内容 |
||||
const [inputMessage, setInputMessage] = useState(''); |
||||
// @ messageList - Object[] - 描述:消息列表 |
||||
const [messageList, setMessageList] = useState([]); |
||||
useEffect(() => { |
||||
setMessageList(props.messageList) |
||||
}, [props.messageList]) |
||||
|
||||
// = 函数名: handleInputMessageChange |
||||
// = 描述: 响应消息内容输入 |
||||
// = 参数: event |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 19:41:26 - |
||||
function handleInputMessageChange(event) { |
||||
setInputMessage(event.target.value) |
||||
} |
||||
|
||||
// = 函数名: handleSendMessage |
||||
// = 描述: 发送消息 |
||||
// = 参数: null |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 19:42:04 - |
||||
function handleSendMessage() { |
||||
props?.sendMessage(inputMessage) |
||||
setInputMessage('') |
||||
} |
||||
return <div className={css.messageWindow}> |
||||
<div className={css.container}> |
||||
<div className={css.body}> |
||||
<div className={css.container}> |
||||
{ |
||||
messageList.map(item => <div key={item.timeId} className={item.isMe ? [css.messageBox,css.myMessageBox].join(' ') : css.messageBox}> |
||||
<div> |
||||
<div> |
||||
<div>{item.nickname}</div> | |
||||
<div>{item.timeId}</div> |
||||
</div> |
||||
<div>{item.message}</div> |
||||
</div> |
||||
</div>) |
||||
} |
||||
</div> |
||||
</div> |
||||
<div className={css.footer}> |
||||
<textarea value={inputMessage} onChange={handleInputMessageChange}></textarea> |
||||
<div className={css.sendButton} onClick={handleSendMessage}>发送</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
} |
@ -0,0 +1,110 @@ |
||||
.messageWindow{ |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
overflow: hidden; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
& > div.container{ |
||||
position: relative; |
||||
min-width: 800px; |
||||
max-width: 1200px; |
||||
width: auto; |
||||
overflow: hidden; |
||||
height: 80%; |
||||
min-height: 700px; |
||||
max-height: 900px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
background: #9D44C099; |
||||
border-radius: 10px; |
||||
box-sizing: border-box; |
||||
padding: 15px; |
||||
box-shadow: 0 0 20px -5px #33333333; |
||||
& > div.body{ |
||||
position: relative; |
||||
flex: 1; |
||||
background: #F7E987; |
||||
border-radius: 10px; |
||||
box-shadow: 0 0 10px -5px #33333399 inset; |
||||
margin-bottom: 15px; |
||||
padding: 15px; |
||||
overflow: hidden; |
||||
& > div.container{ |
||||
position: relative; |
||||
max-height: 100%; |
||||
box-sizing: border-box; |
||||
overflow: auto; |
||||
&>div.messageBox{ |
||||
position: relative; |
||||
|
||||
& > div{ |
||||
position: relative; |
||||
border-radius: 10px 10px 10px 0; |
||||
padding: 10px; |
||||
box-sizing: border-box; |
||||
box-shadow: 0 0 10px 2px #33333333; |
||||
background: #1BB74Bcc; |
||||
width:fit-content; |
||||
width:-webkit-fit-content; |
||||
width:-moz-fit-content; |
||||
cursor: pointer; |
||||
color: #fefefe; |
||||
margin: 10px 0; |
||||
& > div:first-child{ |
||||
position: relative; |
||||
display: flex; |
||||
} |
||||
} |
||||
} |
||||
&>div.myMessageBox{ |
||||
display: flex; |
||||
justify-content: end; |
||||
& > div{ |
||||
border-radius: 10px 10px 0 10px ; |
||||
background: darkmagenta; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
& > div.footer{ |
||||
position: relative; |
||||
height: 140px; |
||||
flex-shrink: 0; |
||||
background: #fcfcfc; |
||||
border-radius: 10px; |
||||
box-sizing: border-box; |
||||
box-shadow: 0 6px 20px -2px #33333333; |
||||
padding: 15px; |
||||
& > textarea{ |
||||
border:unset; |
||||
outline: unset; |
||||
resize: unset; |
||||
position: relative; |
||||
display: block; |
||||
width: 100%; |
||||
background: #fcfcfc; |
||||
height: 100%; |
||||
overflow: auto; |
||||
} |
||||
& > div.sendButton{ |
||||
position: absolute; |
||||
padding: 5px 15px; |
||||
bottom: 15px; |
||||
right: 15px; |
||||
background: #1BB74B; |
||||
border-radius: 5px; |
||||
cursor: pointer; |
||||
user-select: none; |
||||
transition: all ease-in-out 200ms; |
||||
color: #fefefe; |
||||
//font-weight: 600; |
||||
font-size: 16px; |
||||
&:hover{ |
||||
box-shadow: 0 0 10px 1px #33333333; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,57 @@ |
||||
import css from './index.module.scss' |
||||
import {useEffect, useState} from "react"; |
||||
import { useNavigate} from 'react-router-dom' |
||||
|
||||
export default function Signin(){ |
||||
const navigate = useNavigate() |
||||
// @ host - String - 描述:webSocket连接地址 |
||||
const [host, setHost] = useState('') |
||||
// @ nickname - String - 描述:昵称 |
||||
const [nickname, setNickname] = useState(''); |
||||
useEffect(() => { |
||||
// @ storageHost - String - 描述:来自localStorage的ws链接地址 |
||||
const storageHost = window.localStorage.getItem('wsHost'); |
||||
// @ storageNickname - String - 描述:来自localStorage的ws昵称 |
||||
const storageNickname =window.localStorage.getItem('wsNickname'); |
||||
storageHost && setHost(storageHost) |
||||
storageNickname && setNickname(storageNickname) |
||||
}, [0]); |
||||
// = 函数名: handleHostChange |
||||
// = 描述: 响应修改host输入 |
||||
// = 参数: None |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 16:42:16 - |
||||
function handleHostChange(event) { |
||||
setHost(event.target.value) |
||||
} |
||||
|
||||
// = 函数名: handleChangeNickname |
||||
// = 描述: 响应修改nickName输入 |
||||
// = 参数: None |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 16:42:51 - |
||||
function handleChangeNickname(event) { |
||||
setNickname(event.target.value) |
||||
} |
||||
|
||||
// = 函数名: handleConfirmHost |
||||
// = 描述: 确认host地址 |
||||
// = 参数: None |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 16:42:19 - |
||||
function handleConfirmHost() { |
||||
window.localStorage.setItem('wsHost', host) |
||||
window.localStorage.setItem('wsNickname', nickname) |
||||
navigate('/home') |
||||
} |
||||
return <div className={css.signin}> |
||||
<div> |
||||
<div className={css.input}><input type="text" value={host} onChange={handleHostChange} placeholder="请输入连接地址"/></div> |
||||
<div className={css.input}><input type="text" value={nickname} onChange={handleChangeNickname} placeholder="请输入昵称"/></div> |
||||
<div className={css.button} onClick={handleConfirmHost}>确认连接</div> |
||||
</div> |
||||
</div> |
||||
} |
@ -0,0 +1,45 @@ |
||||
.signin{ |
||||
position: relative; |
||||
height: 100%; |
||||
width: 100%; |
||||
overflow: hidden; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
& > div{ |
||||
position: relative; |
||||
input{ |
||||
all: unset; |
||||
width: 300px; |
||||
background: #00033322; |
||||
padding: 10px 10px; |
||||
font-size: 20px; |
||||
font-weight: bold; |
||||
border-radius: 5px; |
||||
text-align: center; |
||||
} |
||||
&>.input{ |
||||
position: relative; |
||||
margin: 20px 0; |
||||
} |
||||
& > .button{ |
||||
position: relative; |
||||
margin: 0 auto; |
||||
/*div宽度适应文字*/ |
||||
width:fit-content; |
||||
width:-webkit-fit-content; |
||||
width:-moz-fit-content; |
||||
margin-top: 40px; |
||||
padding: 10px 20px; |
||||
border-radius: 5px; |
||||
background: darkmagenta; |
||||
font-weight: bold; |
||||
color: #fefefe; |
||||
cursor: pointer; |
||||
transition: all ease-in-out 300ms; |
||||
&:hover{ |
||||
box-shadow: 0 10px 20px -8px #33333366; |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,72 @@ |
||||
import {useEffect, useLayoutEffect, useState, useRef} from "react"; |
||||
import localforage from 'localforage'; |
||||
import MessageWindow from "../MessageWindow/index.jsx"; |
||||
|
||||
export default function WebSocketClient(){ |
||||
// @ nickname - String - 描述:WebSocket客户端用户名 |
||||
const [nickname, setNickname] = useState(window.localStorage.getItem('wsNickname')) |
||||
// @ ws - WebSocket - 描述:WebSocket客户端 |
||||
const [ws, setWs] = useState(null) |
||||
// @ wsState - Boolean - 描述:websocket状态 |
||||
const [wsState, setWsState] = useState(false); |
||||
// @ webSocketDB - LocalForage - 描述:本地WebSocket消息数据库 |
||||
const [webSocketDB, setWebSocketDB] = useState(null); |
||||
// @ messageList - Object[] - 描述:实时消息列表 |
||||
const [messageList, setMessageList] = useState([]); |
||||
|
||||
useEffect(() => { |
||||
const socket = ws === null && new WebSocket(`ws://${window.localStorage.getItem('wsHost')}:10001`); |
||||
const db = localforage.createInstance({ |
||||
name: "websocket" |
||||
}); |
||||
const msgList = [] |
||||
db.iterate((value, key, iterationNumber) => { |
||||
msgList.push({ |
||||
timeId: key, |
||||
...value |
||||
}) |
||||
}).then(resd => { |
||||
setMessageList(msgList) |
||||
}) |
||||
socket.onopen = event => { |
||||
setWsState(true) |
||||
} |
||||
socket.onerror = event =>{ |
||||
console.error('Error',event) |
||||
} |
||||
socket.onclose = event => { |
||||
setWsState(false) |
||||
setWs(null) |
||||
} |
||||
setWs(socket) |
||||
setWebSocketDB(db) |
||||
return () => { |
||||
socket.readyState === 1 &&socket.close() |
||||
} |
||||
}, [0]) |
||||
|
||||
if(ws){ |
||||
ws.onmessage = event => { |
||||
const msg = JSON.parse(event.data) |
||||
msg.nickname == nickname ? msg.isMe = true : msg.isMe = false; |
||||
setMessageList([...messageList,msg]) |
||||
webSocketDB.setItem(msg.timeId, msg) |
||||
} |
||||
} |
||||
|
||||
// = 函数名: handleSendMessage |
||||
// = 描述: 发送WebSocket消息 |
||||
// = 参数: message | String |
||||
// = 返回值: undefined |
||||
// = 创建人: Nier |
||||
// = 创建时间: 2023-08-30 19:58:30 - |
||||
function handleSendMessage(message) { |
||||
ws.send(JSON.stringify({ |
||||
message, |
||||
timeId: new Date().getTime().toString() + parseInt(Math.random() * 10000000), |
||||
nickname |
||||
})) |
||||
} |
||||
|
||||
return <MessageWindow sendMessage={handleSendMessage} messageList={messageList}/> |
||||
} |
@ -0,0 +1,9 @@ |
||||
import { defineConfig } from 'vite' |
||||
import react from '@vitejs/plugin-react' |
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({ |
||||
plugins: [react()], |
||||
server: { |
||||
host: "0.0.0.0",} |
||||
}) |
@ -0,0 +1,16 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @文件描述: app.js | 实时通信服务端
|
||||
// | @创建时间: 2023-08-30 14:57
|
||||
// | @更新时间: 2023-08-30 14:57
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
import {httpWebSocket} from "./ws.js"; |
||||
|
||||
// http WebSocket
|
||||
httpWebSocket() |
@ -0,0 +1,85 @@ |
||||
// | ------------------------------------------------------------
|
||||
// | @版本: version 0.1
|
||||
// | @创建人: 【Nie-x7129】
|
||||
// | @E-mail: x71291@outlook.com
|
||||
// | @文件描述: ws.js | 通过WebSocket建立服务
|
||||
// | @创建时间: 2023-08-30 15:08
|
||||
// | @更新时间: 2023-08-30 15:08
|
||||
// | @修改记录:
|
||||
// | -*-*-*- (时间--修改人--修改说明) -*-*-*-
|
||||
// | =
|
||||
// | ------------------------------------------------------------
|
||||
|
||||
// 引入WebSocketServer
|
||||
import WebSocket, { WebSocketServer } from 'ws'; |
||||
// 文件操作
|
||||
import { createServer } from 'https'; |
||||
import { readFileSync } from 'fs'; |
||||
|
||||
// = 函数名: httpWebSocket
|
||||
// = 描述: 使用http模式建立WebSocket服务
|
||||
// = 参数: None
|
||||
// = 返回值: undefined
|
||||
// = 创建人: Nier
|
||||
// = 创建时间: 2023-08-30 15:12:57 -
|
||||
async function httpWebSocket() { |
||||
// @ option - Object - 描述:webSocket配置项
|
||||
const option = { |
||||
// 创建服务器 必须提供 port、server、noServer其中任意一个 否则报错
|
||||
port:10001, // 类型:Number 服务器端口号
|
||||
host:'10.10.10.10', // 类型:String 服务器ip(主机名)
|
||||
backlog:50, // 类型:Number 最大等待连接队列的长度
|
||||
// server // 类型:http.Server|https.Server 预先创建的http或https的服务器
|
||||
// path:'message', // 只接受与此路径匹配的连接。
|
||||
// noServer:false, // 类型:Boolean 不启用服务器模式
|
||||
//clientTracking // 指定是否跟踪客户端
|
||||
maxPayload:4096, // 允许的最大消息大小(以字节为单位),默认为 100 MiB(104857600 字节)。
|
||||
} |
||||
const wss = new WebSocketServer(option,() => { |
||||
console.log(`HTTP WebSocket 已启动: ws://${option.host}:${option.port}`) |
||||
}); |
||||
wss.on('connection', function connection(ws) { |
||||
console.log('Conn') |
||||
ws.on('error', console.error); |
||||
ws.on('message', function message(data, isBinary) { |
||||
wss.clients.forEach(function each(client) { |
||||
if (client.readyState === WebSocket.OPEN) { |
||||
client.send(data, { binary: isBinary }); |
||||
} |
||||
}); |
||||
}); |
||||
ws.onclose = event => { |
||||
console.log('Close') |
||||
} |
||||
}); |
||||
} |
||||
|
||||
// = 函数名: httpsWebSocket
|
||||
// = 描述: 使用https模式建立WebSocket服务
|
||||
// = 参数: None
|
||||
// = 返回值: undefined
|
||||
// = 创建人: Nier
|
||||
// = 创建时间: 2023-08-30 15:13:30 -
|
||||
function httpsWebSocket() { |
||||
const server = createServer({ |
||||
cert: readFileSync('/path/to/cert.pem'), |
||||
key: readFileSync('/path/to/key.pem') |
||||
}); |
||||
const wss = new WebSocketServer({ server, port: 10002 }); |
||||
|
||||
wss.on('connection', function connection(ws) { |
||||
ws.on('error', console.error); |
||||
|
||||
ws.on('message', function message(data) { |
||||
console.log('received: %s', data); |
||||
}); |
||||
|
||||
ws.send('something'); |
||||
}); |
||||
} |
||||
|
||||
|
||||
export { |
||||
httpWebSocket, |
||||
httpsWebSocket |
||||
} |
@ -0,0 +1,18 @@ |
||||
{ |
||||
"name": "real-time-communication", |
||||
"version": "1.0.0", |
||||
"description": "", |
||||
"main": "index.js", |
||||
"type": "module", |
||||
"scripts": { |
||||
"test": "echo \"Error: no test specified\" && exit 1", |
||||
"start:server": "node Server/app.js", |
||||
"start:client": "cd Client && npm run dev" |
||||
}, |
||||
"keywords": [], |
||||
"author": "", |
||||
"license": "ISC", |
||||
"dependencies": { |
||||
"ws": "^8.13.0" |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
lockfileVersion: '6.0' |
||||
|
||||
settings: |
||||
autoInstallPeers: true |
||||
excludeLinksFromLockfile: false |
||||
|
||||
dependencies: |
||||
ws: |
||||
specifier: ^8.13.0 |
||||
version: 8.13.0 |
||||
|
||||
packages: |
||||
|
||||
/ws@8.13.0: |
||||
resolution: {integrity: sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==} |
||||
engines: {node: '>=10.0.0'} |
||||
peerDependencies: |
||||
bufferutil: ^4.0.1 |
||||
utf-8-validate: '>=5.0.2' |
||||
peerDependenciesMeta: |
||||
bufferutil: |
||||
optional: true |
||||
utf-8-validate: |
||||
optional: true |
||||
dev: false |
Loading…
Reference in new issue