From f7eaf63c574af0fca0b66c4919f3f81f0280032e Mon Sep 17 00:00:00 2001 From: LoV432 Date: Mon, 4 Mar 2024 02:06:39 +0500 Subject: [PATCH] feat: connected devices indicator --- .../ConnectedDevicesBoundarie.client.tsx | 27 +++++++++ .../ConnectedDevicesBoundarie.server.tsx | 21 +++++++ app/components/user-cards/UserCard.client.tsx | 8 +++ app/page.tsx | 9 ++- lib/get-connected-devices.tsx | 60 +++++++++++++++++++ router_setup.sh | 16 ++++- 6 files changed, 137 insertions(+), 4 deletions(-) create mode 100644 app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client.tsx create mode 100644 app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.server.tsx create mode 100644 lib/get-connected-devices.tsx diff --git a/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client.tsx b/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client.tsx new file mode 100644 index 0000000..95131a8 --- /dev/null +++ b/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client.tsx @@ -0,0 +1,27 @@ +'use client'; +import { useSetAtom, atom } from 'jotai'; +import { useEffect, useMemo } from 'react'; +import { getConnectedDevices } from '@/lib/get-connected-devices'; +export const allConnectedDevices = atom>([]); + +export default function ConnectedDevicesWrapper({ + children, + connectedDevices: connectedDevices +}: { + children: React.ReactNode; + connectedDevices: string[]; +}) { + const setConnectedDevices = useSetAtom(allConnectedDevices); + useMemo(() => { + setConnectedDevices(connectedDevices); + }, []); + useEffect(() => { + setInterval(() => { + getConnectedDevices().then((connectedDevices) => { + if ('error' in connectedDevices) return; + setConnectedDevices(connectedDevices); + }); + }, 5000); + }); + return <>{children}; +} diff --git a/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.server.tsx b/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.server.tsx new file mode 100644 index 0000000..af2013e --- /dev/null +++ b/app/components/boundaries/ConnectedDevices/ConnectedDevicesBoundarie.server.tsx @@ -0,0 +1,21 @@ +import { getConnectedDevices } from '@/lib/get-connected-devices'; +import ConnectedDevicesWrapper from './ConnectedDevicesBoundarie.client'; + +export default async function ConnectedDevicesBoundarie({ + children +}: { + children: React.ReactNode; +}) { + const connectedDevices = await getConnectedDevices(); + if ('error' in connectedDevices) + return ( + + {children} + + ); + return ( + + {children} + + ); +} diff --git a/app/components/user-cards/UserCard.client.tsx b/app/components/user-cards/UserCard.client.tsx index f90146f..3d1508f 100644 --- a/app/components/user-cards/UserCard.client.tsx +++ b/app/components/user-cards/UserCard.client.tsx @@ -13,12 +13,15 @@ import { unblockDevice as unblockUser } from '@/lib/block-user-script.server'; import { allBlockedDevices as allBlockedDevicesState } from '../boundaries/BlockedDevices/BlockedDevicesBoundarie.client'; +import { allConnectedDevices as allConnectedDevicesState } from '../boundaries/ConnectedDevices/ConnectedDevicesBoundarie.client'; export default function UserCard({ user }: { user: userReturnType }) { const [localUpdateTime, setLocalUpdateTime] = useState(''); const [showDetails, setShowDetails] = useState(false); const [showToast, setShowToast] = useState(false); const allBlockedDevices = useAtomValue(allBlockedDevicesState); const isBlocked = allBlockedDevices.includes(user.mac_address); + const allConnectedDevices = useAtomValue(allConnectedDevicesState); + const isConnected = allConnectedDevices.includes(user.mac_address); function copyText(text: string) { // TODO: This whole copy/toast logic is duplicate of DashboardCardCurrentStatus.client.tsx. Find a way to merge? @@ -45,6 +48,11 @@ export default function UserCard({ user }: { user: userReturnType }) {
+
+ {isConnected && ( + + )} +
- - - + + + + +
diff --git a/lib/get-connected-devices.tsx b/lib/get-connected-devices.tsx new file mode 100644 index 0000000..5547c52 --- /dev/null +++ b/lib/get-connected-devices.tsx @@ -0,0 +1,60 @@ +'use server'; +import { getToken } from './get-token'; + +type connectedDeviceResponseType = { + id: number; + result?: [0, { stdout: string }?]; +}; + +export async function getConnectedDevices() { + let token = (await getToken()) as string; + let getConnectedDevicesResponse = await getConnectedDevicesRequest(token); + if ( + !getConnectedDevicesResponse.result || + !getConnectedDevicesResponse.result[1] + ) { + let newToken = await getToken(true); + if (!newToken) { + console.log('getConnectedDevices: Token not found'); + return { error: 'Token not found' }; + } + getConnectedDevicesResponse = await getConnectedDevicesRequest(newToken); + if ( + !getConnectedDevicesResponse.result || + !getConnectedDevicesResponse.result[1] + ) { + console.log('getConnectedDevices: Something went wrong'); + return { error: 'Something went wrong' }; + } + } + const connectedDevicesSplit = + getConnectedDevicesResponse.result[1].stdout.split('\n'); + let connectedDevices = connectedDevicesSplit + .map((device) => { + if (!device) return; + const deviceSplit = device.split(' '); + return deviceSplit[4]; + }) + .filter((device) => device !== undefined) as string[]; + return connectedDevices; +} + +async function getConnectedDevicesRequest(token: string) { + let requestBody = { + jsonrpc: '2.0', + id: 1, + method: 'call', + params: [token, 'file', 'exec', { command: '/etc/neigh-probe' }] + }; + + let makeRequest = await fetch(`${process.env.ROUTER_URL}/ubus`, { + method: 'POST', + body: JSON.stringify(requestBody), + headers: { + 'Content-Type': 'application/json' + }, + cache: 'no-cache' + }); + + return (await makeRequest.json()) as connectedDeviceResponseType; +} diff --git a/router_setup.sh b/router_setup.sh index 81b8fc2..e4ac395 100644 --- a/router_setup.sh +++ b/router_setup.sh @@ -89,7 +89,8 @@ json_content='{ "/etc/wrtbwmon-update": ["exec"], "/proc/uptime": ["read"], "/etc/pppoe-status": ["exec"], - "/etc/block-device": ["exec"] + "/etc/block-device": ["exec"], + "/etc/neigh-probe": ["exec"] } } } @@ -150,6 +151,19 @@ echo "Script created /etc/wrtbwmon-update" ############################# +# Create connected device script +############################# +content=$(cat <<'END_SCRIPT' +#!/bin/sh + +ip -4 neigh show nud reachable nud stale nud permanent nud delay +END_SCRIPT +) +echo "$content" > /etc/neigh-probe +chmod 755 /etc/neigh-probe +echo "Script created /etc/neigh-probe" +############################# + # Create user block script #############################