From bd8a43f40ee5de25b4e7d1ce33944cd498b094d7 Mon Sep 17 00:00:00 2001 From: Martin Berg Alstad <600878@stud.hvl.no> Date: Tue, 16 May 2023 21:55:56 +0200 Subject: [PATCH] Started testing webSockets --- .../ClientApp/package-lock.json | 33 +---------- pac-man-board-game/ClientApp/package.json | 4 +- .../ClientApp/src/hooks/useWebSocket.ts | 0 .../ClientApp/src/pages/Counter.tsx | 28 +++++++++ pac-man-board-game/ClientApp/vite.config.ts | 5 +- .../Controllers/WsController.cs | 59 ++++++++++++++++++- 6 files changed, 91 insertions(+), 38 deletions(-) create mode 100644 pac-man-board-game/ClientApp/src/hooks/useWebSocket.ts diff --git a/pac-man-board-game/ClientApp/package-lock.json b/pac-man-board-game/ClientApp/package-lock.json index b172d48..4c4148f 100644 --- a/pac-man-board-game/ClientApp/package-lock.json +++ b/pac-man-board-game/ClientApp/package-lock.json @@ -16,14 +16,12 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.9.0", - "web-vitals": "^2.1.4", - "ws": "^8.13.0" + "web-vitals": "^2.1.4" }, "devDependencies": { "@types/jest": "^29.5.1", "@types/react": "^18.2.6", "@types/react-dom": "^18.2.4", - "@types/ws": "^8.5.4", "@vitejs/plugin-react": "^4.0.0", "ajv": "^8.12.0", "autoprefixer": "^10.4.14", @@ -3065,15 +3063,6 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, - "node_modules/@types/ws": { - "version": "8.5.4", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.4.tgz", - "integrity": "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, "node_modules/@types/yargs": { "version": "17.0.24", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", @@ -8109,26 +8098,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "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 - } - } - }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/pac-man-board-game/ClientApp/package.json b/pac-man-board-game/ClientApp/package.json index 06841fa..9fe7021 100644 --- a/pac-man-board-game/ClientApp/package.json +++ b/pac-man-board-game/ClientApp/package.json @@ -11,14 +11,12 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.9.0", - "web-vitals": "^2.1.4", - "ws": "^8.13.0" + "web-vitals": "^2.1.4" }, "devDependencies": { "@types/jest": "^29.5.1", "@types/react": "^18.2.6", "@types/react-dom": "^18.2.4", - "@types/ws": "^8.5.4", "@vitejs/plugin-react": "^4.0.0", "ajv": "^8.12.0", "autoprefixer": "^10.4.14", diff --git a/pac-man-board-game/ClientApp/src/hooks/useWebSocket.ts b/pac-man-board-game/ClientApp/src/hooks/useWebSocket.ts new file mode 100644 index 0000000..e69de29 diff --git a/pac-man-board-game/ClientApp/src/pages/Counter.tsx b/pac-man-board-game/ClientApp/src/pages/Counter.tsx index 35d5280..4adca61 100644 --- a/pac-man-board-game/ClientApp/src/pages/Counter.tsx +++ b/pac-man-board-game/ClientApp/src/pages/Counter.tsx @@ -1,5 +1,26 @@ import React from "react"; +const ws = new WebSocket("wss://localhost:3000/api/"); + +let isWsOpen = false; + +ws.onopen = () => { + isWsOpen = true; + console.log("WebSocket Client Connected"); +}; + +ws.onmessage = (data) => { + console.log(`Received message: ${data}`); +}; + +ws.onerror = (err) => { + console.error(err); +}; + +ws.onclose = () => { + console.log("WebSocket Client Disconnected"); +}; + export const Counter: Component = () => { const [currentCount, setCurrentCount] = React.useState(0); @@ -8,6 +29,13 @@ export const Counter: Component = () => { setCurrentCount(currentCount + 1); } + React.useEffect(() => { + + if (isWsOpen) { + ws.send(`Current count: ${currentCount}`); + } + }, [currentCount]); + return (

Counter

diff --git a/pac-man-board-game/ClientApp/vite.config.ts b/pac-man-board-game/ClientApp/vite.config.ts index 64ffa17..9d7a275 100644 --- a/pac-man-board-game/ClientApp/vite.config.ts +++ b/pac-man-board-game/ClientApp/vite.config.ts @@ -1,11 +1,11 @@ import react from "@vitejs/plugin-react"; -import { defineConfig } from "vite"; +import {defineConfig} from "vite"; // @ts-ignore import fs from "fs"; // @ts-ignore import path from "path"; -import { execSync } from "child_process"; +import {execSync} from "child_process"; export default defineConfig({ plugins: [react()], @@ -18,6 +18,7 @@ export default defineConfig({ "/api": { changeOrigin: true, secure: false, + ws: true, rewrite: (path) => path.replace(/^\/api/, "/api"), // target taken from src/setupProxy.js in ASP.NET React template target: process.env.ASPNETCORE_HTTPS_PORT diff --git a/pac-man-board-game/Controllers/WsController.cs b/pac-man-board-game/Controllers/WsController.cs index 1a6c854..819a1b7 100644 --- a/pac-man-board-game/Controllers/WsController.cs +++ b/pac-man-board-game/Controllers/WsController.cs @@ -1,3 +1,5 @@ +using System.Net.WebSockets; +using System.Text; using Microsoft.AspNetCore.Mvc; namespace pacMan.Controllers; @@ -6,9 +8,64 @@ namespace pacMan.Controllers; [Route("api/[controller]")] public class WsController : ControllerBase { + private readonly ILogger _logger; + + public WsController(ILogger logger) + { + _logger = logger; + } + [HttpGet] - public void TestGet() + public async void TestWebSocket() { // TODO test websocket https://learn.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-7.0 + if (HttpContext.WebSockets.IsWebSocketRequest) + { + var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync(); + _logger.Log(LogLevel.Information, "Accepted WebSocket connection from {ConnectionId}", + HttpContext.Connection.Id); + await Echo(webSocket); + } + else + { + HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest; + } + } + + private async Task Echo(WebSocket webSocket) + { + var buffer = new byte[1024 * 4]; + WebSocketReceiveResult? receiveResult; + + // While the WebSocket connection remains open run a simple loop that receives data and sends it back. + do + { + // Receive the request and store it in a buffer + receiveResult = await webSocket.ReceiveAsync( + new ArraySegment(buffer), CancellationToken.None); + + _logger.Log(LogLevel.Information, "Received {Count} bytes", receiveResult.Count); + + if (receiveResult.CloseStatus.HasValue) break; + var msg = Encoding.UTF8.GetString(buffer); + _logger.Log(LogLevel.Information, "Received {Message}", msg); + + // Send the request back to the client + await webSocket.SendAsync( + new ArraySegment(buffer, 0, receiveResult.Count), + receiveResult.MessageType, + receiveResult.EndOfMessage, + CancellationToken.None); + + _logger.Log(LogLevel.Information, "Sent {Count} bytes", receiveResult.Count); + } while (true); + + // Close the WebSocket connection + await webSocket.CloseAsync( + receiveResult.CloseStatus.Value, + receiveResult.CloseStatusDescription, + CancellationToken.None); + _logger.Log(LogLevel.Information, "Closed WebSocket connection {ConnectionId}", + HttpContext.Connection.Id); } } \ No newline at end of file