CrashCourse on basic ws

This commit is contained in:
2026-01-31 07:04:01 -06:00
parent 9eb51b7e9f
commit e3f990815b
4 changed files with 199 additions and 10 deletions

75
index.html Normal file
View 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
View File

@@ -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"
}
} }
} }
} }

View File

@@ -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",

View File

@@ -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")