CrashCourse on basic ws
This commit is contained in:
75
index.html
Normal file
75
index.html
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Websocket tutorial</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: sans-serif; padding: 20px; background: #121212 ; color: #ffff;}
|
||||||
|
#log {background: #0000; padding: 10px; height: 300px; overflow-y: scroll; border: 1px solid #333;}
|
||||||
|
.status-on {color: #00ff00}
|
||||||
|
.status-off {color: #ff0000;}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>WebSocket Broadcast Console</h1>
|
||||||
|
<p id="status" class="status-off">Connecting...</p>
|
||||||
|
|
||||||
|
<form id="message-form">
|
||||||
|
<input
|
||||||
|
id="message-input"
|
||||||
|
type="text"
|
||||||
|
placeholder="Send cargo..."
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
type="submit">
|
||||||
|
Deploy Message
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
<h3>Live Steam Logs:</h3>
|
||||||
|
<pre id="log"></pre>
|
||||||
|
</body>
|
||||||
|
<script>
|
||||||
|
const statusEl = document.getElementById('status')
|
||||||
|
const log = document.getElementById('log')
|
||||||
|
const input = document.getElementById('message-input')
|
||||||
|
|
||||||
|
// 1. creates the connection
|
||||||
|
const s = new WebSocket('ws://localhost:8081')
|
||||||
|
|
||||||
|
const appendLog = (label, message) =>{
|
||||||
|
const entry = `${new Date().toLocaleTimeString()} ${label}: ${message}\n`
|
||||||
|
log.textContent = entry + log.textContent
|
||||||
|
}
|
||||||
|
|
||||||
|
s.addEventListener('open', ()=>{
|
||||||
|
statusEl.textContent = 'CONNECTED: ws://localhost:8081'
|
||||||
|
statusEl.className = 'status-on'
|
||||||
|
appendLog('[SYSTEM]', 'Tunnel Established')
|
||||||
|
})
|
||||||
|
|
||||||
|
s.addEventListener('close', ()=>{
|
||||||
|
statusEl.textContent = 'Disconnected from: ws://localhost:8081'
|
||||||
|
statusEl.className = 'status-off'
|
||||||
|
appendLog('[SYSTEM]', 'Tunnel Disconnected')
|
||||||
|
})
|
||||||
|
|
||||||
|
s.addEventListener('message', (e)=>{
|
||||||
|
appendLog('[RECEIVED]', e.data)
|
||||||
|
})
|
||||||
|
|
||||||
|
document.getElementById("message-form").addEventListener('submit', (e)=>{
|
||||||
|
e.preventDefault()
|
||||||
|
if(s.readyState !== WebSocket.OPEN){
|
||||||
|
appendLog('[ERROR]', 'Not Connected')
|
||||||
|
}
|
||||||
|
|
||||||
|
const msg = input.value.trim()
|
||||||
|
s.send(msg)
|
||||||
|
appendLog('[SENT]', msg)
|
||||||
|
input.value = ''
|
||||||
|
})
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
96
package-lock.json
generated
96
package-lock.json
generated
@@ -9,7 +9,8 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0",
|
||||||
|
"wscat": "^6.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.1.0",
|
||||||
@@ -36,6 +37,81 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/agent-base": {
|
||||||
|
"version": "7.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||||
|
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "12.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz",
|
||||||
|
"integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/debug": {
|
||||||
|
"version": "4.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
|
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ms": "^2.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"supports-color": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/https-proxy-agent": {
|
||||||
|
"version": "7.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||||
|
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.2",
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ms": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/mute-stream": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || >=20.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/read": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/read/-/read-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-uRfX6K+f+R8OOrYScaM3ixPY4erg69f8DN6pgTvMcA9iRc8iDhwrA4m3Yu8YYKsXJgVvum+m8PkRboZwwuLzYA==",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"mute-stream": "^2.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.17.0 || >=20.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/undici-types": {
|
"node_modules/undici-types": {
|
||||||
"version": "7.16.0",
|
"version": "7.16.0",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz",
|
||||||
@@ -63,6 +139,24 @@
|
|||||||
"optional": true
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"node_modules/wscat": {
|
||||||
|
"version": "6.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/wscat/-/wscat-6.1.0.tgz",
|
||||||
|
"integrity": "sha512-x6gEZvITvqWslR38DoBfnMi37ZBUGsG9rTkGc/200sEfSs1JwgKLZYQeqa0vlu3bxXQV7hEHI4NF7KQmYIzB2A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^12.1.0",
|
||||||
|
"https-proxy-agent": "^7.0.5",
|
||||||
|
"read": "^4.0.0",
|
||||||
|
"ws": "^8.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"wscat": "bin/wscat"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
"name": "websocketcourse",
|
"name": "websocketcourse",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "server.js",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"dev": "node --watch server.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -13,9 +14,9 @@
|
|||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"type": "commonjs",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ws": "^8.19.0"
|
"ws": "^8.19.0",
|
||||||
|
"wscat": "^6.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^25.1.0",
|
"@types/node": "^25.1.0",
|
||||||
|
|||||||
27
server.js
27
server.js
@@ -1,8 +1,16 @@
|
|||||||
import {WebSocketServer} from 'ws'
|
import {WebSocketServer, WebSocket} from 'ws'
|
||||||
|
|
||||||
const wss = new WebSocketServer({port: 8081})
|
const wss = new WebSocketServer({port: 8081})
|
||||||
|
|
||||||
// conmnection event
|
// connection event
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connection types
|
||||||
|
* 0: connecting
|
||||||
|
* 1: open (the only state where you can safely .send())
|
||||||
|
* 2: Closing
|
||||||
|
* 3: closed
|
||||||
|
*/
|
||||||
|
|
||||||
wss.on('connection', (s, r)=>{
|
wss.on('connection', (s, r)=>{
|
||||||
const ip = r.socket.remoteAddress
|
const ip = r.socket.remoteAddress
|
||||||
@@ -11,8 +19,19 @@ wss.on('connection', (s, r)=>{
|
|||||||
const message = rawData.toString()
|
const message = rawData.toString()
|
||||||
console.log({rawData})
|
console.log({rawData})
|
||||||
|
|
||||||
wss.clients.forEach((c)=>{
|
wss.clients.forEach((client)=>{
|
||||||
if(c.readyState === 1) c.send(`Server Broadcast: ${message}`)
|
// can use readyState to be === 1 or WebSocket.OPEN they mean the same thing
|
||||||
|
if(client.readyState === WebSocket.OPEN) client.send(`Server Broadcast: ${message}`)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
s.on("error", ()=>{
|
||||||
|
console.error(`Error: ${err.message}: ${ip}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
s.on('close', ()=>{
|
||||||
|
console.log('Client Disconnected')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log("Server Running on 8081")
|
||||||
Reference in New Issue
Block a user