From 692c6690d4bec7676a6171d4c9ecce2d9928a27f Mon Sep 17 00:00:00 2001 From: Nasar Eddaoui Date: Fri, 3 May 2024 22:29:06 +0700 Subject: [PATCH] add websocket support --- app/components/input.tsx | 29 +++++++++++++++++++++++ app/components/socket.tsx | 47 +++++++++++++++++++++++++++++++++++++ app/lib/websocket/socket.ts | 28 ++++++++++++++++++++++ app/model/websocket.ts | 11 +++++++++ app/page.tsx | 24 ++++++++++++++++++- package-lock.json | 10 ++++++++ package.json | 11 +++++---- 7 files changed, 154 insertions(+), 6 deletions(-) create mode 100644 app/components/input.tsx create mode 100644 app/components/socket.tsx create mode 100644 app/lib/websocket/socket.ts create mode 100644 app/model/websocket.ts diff --git a/app/components/input.tsx b/app/components/input.tsx new file mode 100644 index 0000000..7c9defe --- /dev/null +++ b/app/components/input.tsx @@ -0,0 +1,29 @@ +import { SyntheticEvent } from 'react'; + +type InputEvent = (event: SyntheticEvent) => void; + +type input = { + name: string; + value: string; + onChange: InputEvent; +}; + +export default function Input({ name, value, onChange }: input): JSX.Element { + return ( +
+ +
+ +
+
+ ); +} diff --git a/app/components/socket.tsx b/app/components/socket.tsx new file mode 100644 index 0000000..4dc84dd --- /dev/null +++ b/app/components/socket.tsx @@ -0,0 +1,47 @@ +'use client'; + +import React, { useEffect, useState } from 'react'; +import { Websocket } from '../lib/websocket/socket'; + +type Url = { url: string }; + +export default function Socket({ url }: Url): React.JSX.Element { + const [socket, setSocket] = useState(); + + const cleanup = () => { + try { + console.log('clean up lose connection'); + console.log(socket); + + socket?.Stop(1000); + } catch (err) { + console.error(err); + } + }; + + const start = () => { + try { + if (!socket?.Alive()) { + socket?.Start(url); + setSocket(socket); + } else socket?.Stop(1000); + } catch (err) { + console.error(err); + } + }; + + useEffect(() => { + setSocket(new Websocket()); + }, []); + + return ( +
+ +
+ ); +} diff --git a/app/lib/websocket/socket.ts b/app/lib/websocket/socket.ts new file mode 100644 index 0000000..af34518 --- /dev/null +++ b/app/lib/websocket/socket.ts @@ -0,0 +1,28 @@ +import { DEAD, ISocket, LIVE } from '@/app/model/websocket'; +export class Websocket implements ISocket { + private socket?: WebSocket; + + Alive(): boolean { + return this.socket != null && this.socket.readyState == this.socket.OPEN; + } + + Start(url: string): void { + if (this.Alive()) throw Error(LIVE); + + this.socket = new WebSocket(url, ['ocpp1.6']); + console.log('Websocket connection was successful'); + } + + Stop(code?: number): void { + if (!this.Alive()) throw new Error(DEAD); + + console.log('closing socket'); + this.socket!.close(code ?? 1000); + } + + Send(message: string) { + if (!this.Alive()) throw new Error(DEAD); + + this.socket!.send(message); + } +} diff --git a/app/model/websocket.ts b/app/model/websocket.ts new file mode 100644 index 0000000..f749314 --- /dev/null +++ b/app/model/websocket.ts @@ -0,0 +1,11 @@ +const LIVE = 'web socket client is already initialized'; +const DEAD = 'web socket client is dead, open a new connection'; + +interface ISocket { + Alive(): boolean; + Start(url: string, event: CloseEvent): void; + Stop(code: number): void; +} + +export type { ISocket }; +export { LIVE, DEAD }; diff --git a/app/page.tsx b/app/page.tsx index 1cd722d..27caf1a 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,5 +1,27 @@ 'use client'; +import { SyntheticEvent, useState } from 'react'; +import Websocket from './components/socket'; +import Input from './components/input'; + export default function Home() { - return
Hello world
; + const [url, setUrl] = useState( + 'ws://localhost:8080/ocpp/JwNpTpPxPm/CHR202305102' + ); + + const onChange = (event: SyntheticEvent) => { + console.log(event.currentTarget.value); + + setUrl(event.currentTarget.value); + }; + + return ( +
+

OCPP 1.6-J EVSE Test tool

+
+ + +
+
+ ); } diff --git a/package-lock.json b/package-lock.json index 56694b5..a5b7bdd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/ws": "^8.5.10", "eslint": "^8", "eslint-config-next": "14.2.3", "postcss": "^8", @@ -482,6 +483,15 @@ "@types/react": "*" } }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/parser": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.2.0.tgz", diff --git a/package.json b/package.json index b7b559e..f192e42 100644 --- a/package.json +++ b/package.json @@ -9,18 +9,19 @@ "lint": "next lint" }, "dependencies": { + "next": "14.2.3", "react": "^18", - "react-dom": "^18", - "next": "14.2.3" + "react-dom": "^18" }, "devDependencies": { - "typescript": "^5", "@types/node": "^20", "@types/react": "^18", "@types/react-dom": "^18", + "@types/ws": "^8.5.10", + "eslint": "^8", + "eslint-config-next": "14.2.3", "postcss": "^8", "tailwindcss": "^3.4.1", - "eslint": "^8", - "eslint-config-next": "14.2.3" + "typescript": "^5" } }