From fc845f2661be61b1a86501eed306cb0d7cb60d73 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Tue, 18 Jan 2022 22:03:20 +0100 Subject: Show historic requests for the session on page load --- src/components/App/App.tsx | 46 +++++++++++++++++++++++-------- src/hooks/useRequests.tsx | 69 ++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 92 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 3a7fe9b..e361aa5 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import useRequests, {RequestResponse} from "../../hooks/useRequests"; +import useRequests, {RequestResponse, ReadyState} from "../../hooks/useRequests"; import {useEffect, useMemo, useState} from "react"; import styles from './App.module.scss'; @@ -11,34 +11,56 @@ interface Config { url: string } +type ReadyStateMap = { + [ReadyState.CONNECTING]: string, + [ReadyState.OPEN]: string, + [ReadyState.CLOSING]: string, + [ReadyState.CLOSED]: string, +} + +const statusMap: ReadyStateMap = { + [ReadyState.CONNECTING]: '🔴', + [ReadyState.OPEN]: '🟢', + [ReadyState.CLOSING]: '🔴', + [ReadyState.CLOSED]: '🔴', +} + export default function App() { + const [config, setConfig]= useState(null) + + const { calls, readyState } = useRequests({ + onConnect: async () => { + const response = await fetch(`http://${getHost()}/config/`) + const config = await response.json() + setConfig(config) + } + }); + useEffect(() => { - fetch(`http://${getHost()}/config/`) - .then(response => response.json() as Promise) - .then(setConfig) - }, []) + const url = new URL(config?.url ?? 'https://loading...'); + document.title = `${statusMap[readyState]} ${url.host} | TTUN`; + }, [readyState, config?.url]) - const requests = useRequests(); const [selectedRequestIndex, setSelectedRequestIndex] = useState(null); const selectedRequest = useMemo(() => ( selectedRequestIndex === null ? null - : requests[selectedRequestIndex] - ), [selectedRequestIndex, requests]); + : calls[selectedRequestIndex] + ), [selectedRequestIndex, calls]); return config && (
- TTUN + {statusMap[readyState]} TTUN {config.url}
    { - requests.length > 0 - ? requests.slice(0).reverse().map((requestResponse, index) => ( -
  • setSelectedRequestIndex(requests.length - index - 1)} key={`request-${index}`}> + calls.length > 0 + ? calls.slice(0).reverse().map((requestResponse, index) => ( +
  • setSelectedRequestIndex(calls.length - index - 1)} key={`request-${index}`}>
  • )) diff --git a/src/hooks/useRequests.tsx b/src/hooks/useRequests.tsx index 3ad5cc7..2b8393e 100644 --- a/src/hooks/useRequests.tsx +++ b/src/hooks/useRequests.tsx @@ -33,25 +33,67 @@ interface Response { payload: ResponsePayload, } +interface Historic { + type: 'historic' + payload: (Request | Response)[] +} + export interface RequestResponse { request: RequestPayload response?: ResponsePayload } -export default function useRequests(): RequestResponse[] { +export enum ReadyState { + CONNECTING = 0, + OPEN = 1, + CLOSING = 2, + CLOSED = 3, +} + +export interface useRequestsProps { + onConnect: () => Promise +} + +export interface UseRequests { + calls: RequestResponse[] + readyState: ReadyState +} + +export default function useRequests({ onConnect }: useRequestsProps): UseRequests { const wsHost = useMemo(getHost, []); - const connect = useCallback(() => new WebSocket(`ws://${wsHost}/inspect/`), [wsHost]) const [requests, setRequests] = useState([]); const [responses, setResponses] = useState([]); - const [ws, setWs] = useState(() => connect()); + + + const connect = useCallback(() => ( + new WebSocket(`ws://${wsHost}/inspect/`) + ), [wsHost]); + + const [ws, setWs] = useState(() => connect()); + const [readyState, setReadyState] = useState(ws.readyState); useEffect(() => { - const reconnect = () => setWs(() => connect()) + setReadyState(ws.readyState); + + const onClose = () => { + setReadyState(ws.readyState); + setWs(connect()); + } + const onOpen = () => { + onConnect(); + setReadyState(ws.readyState); + } const onMessage = ({ data }) => { - const { type, payload } = JSON.parse(data) as Request | Response + const { type, payload } = JSON.parse(data) as Historic | Request | Response switch (type) { + case 'historic': + const requests = (payload as (Request | Response)[]).filter(({ type }) => type === 'request'); + const responses = (payload as (Request | Response)[]).filter(({ type }) => type === 'response'); + setRequests((rqs) => [...rqs, ...requests.map(({ payload }) => payload as RequestPayload)]); + setResponses((rps) => [...rps, ...responses.map(({ payload }) => payload as ResponsePayload)]); + break case 'request': setRequests((rqs) => [...rqs, payload as RequestPayload]) break @@ -62,16 +104,21 @@ export default function useRequests(): RequestResponse[] { } ws.addEventListener('message', onMessage) - ws.addEventListener('close', reconnect) + ws.addEventListener('close', onClose) + ws.addEventListener('open', onOpen) return () => { ws.removeEventListener('message', onMessage); - ws.removeEventListener('close', reconnect); + ws.removeEventListener('close', onClose); + ws.removeEventListener('open', onOpen) } }, [ws]) - return useMemo(() => requests.map((request) => ({ - request: request, - response: responses.find(({ id }) => id === request.id) - })), [requests, responses]) + return { + calls: useMemo(() => requests.map((request) => ({ + request: request, + response: responses.find(({id}) => id === request.id) + })), [requests, responses]), + readyState, + } } -- cgit v1.2.3