Skip to content

Commit

Permalink
Merge pull request #264 from binbat/feat/web-persist-token
Browse files Browse the repository at this point in the history
feat(web): persist token to localStorage
  • Loading branch information
a-wing authored Dec 23, 2024
2 parents aac6fb6 + 346abbd commit 368017b
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 32 deletions.
4 changes: 2 additions & 2 deletions web/liveman/components/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function useInput(label: string, type = 'text') {

export interface LoginProps {
show: boolean;
onSuccess?: (token: string) => void;
onSuccess?: (tokenType: string, tokenValue: string) => void;
}

export function Login({ show, onSuccess }: LoginProps) {
Expand Down Expand Up @@ -76,7 +76,7 @@ export function Login({ show, onSuccess }: LoginProps) {
const tk = `${tokenType} ${tokenValue}`;
livemanApi.setAuthToken(tk);
sharedApi.setAuthToken(tk);
onSuccess?.(tokenValue);
onSuccess?.(tokenType, tokenValue);
} catch (e) {
livemanApi.setAuthToken('');
sharedApi.setAuthToken('');
Expand Down
16 changes: 11 additions & 5 deletions web/liveman/components/nodes-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ export function NodesTable() {
const tokenContext = useContext(TokenContext);

useEffect(() => {
if (tokenContext.token.length > 0) {
nodes.updateData();
}
nodes.updateData();
}, [tokenContext.token]);

return (
Expand Down Expand Up @@ -57,7 +55,7 @@ export function NodesTable() {
<span>{n.status}</span>
<span>{n.duration}</span>
<NodeStrategyLabel strategy={n.strategy} />
<Link href={location.href + '?nodes=' + n.alias} target="_blank">{location.href + '?nodes=' + n.alias}</Link>
<NodeLink node={n} />
</Table.Row>
) : <tr><td colspan={5} className="text-center">N/A</td></tr>}
</Table.Body>
Expand All @@ -76,7 +74,6 @@ function NodeStrategyLabel({ strategy }: NodeStrategyLabelProps) {
return (
<Dropdown hover>
<Dropdown.Toggle button={false} className="font-mono flex items-center gap-1">
{/* <InformationCircleIcon className="size-4" /> */}
<span>{entries[0].join(' = ')}</span>
<EllipsisHorizontalIcon className="size-4" />
</Dropdown.Toggle>
Expand All @@ -95,3 +92,12 @@ function NodeStrategyLabel({ strategy }: NodeStrategyLabelProps) {
</Dropdown>
);
}

function NodeLink({ node }: { node: Node }) {
const urlObject = new URL(location.href);
urlObject.searchParams.set('nodes', node.alias);
const url = urlObject.toString();
return (
<Link href={url} target="_blank">{url}</Link>
);
}
35 changes: 20 additions & 15 deletions web/liveman/liveman.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,44 @@
import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { Button } from 'react-daisyui';

import { type Stream } from '@/shared/api';
import { useNeedAuthorization } from '@/shared/hooks/use-need-authorization';
import { StreamsTable } from '@/shared/components/streams-table';
import { PageLayout } from '@/shared/components/page-layout';

import * as api from './api';
import { Login } from './components/login';
import { type LoginProps, Login } from './components/login';
import { NodesTable } from './components/nodes-table';
import { type IStreamTokenDialog, StreamTokenDialog } from './components/dialog-token';

const TOKEN_KEY = 'liveman_auth_token';
const initialToken = localStorage.getItem(TOKEN_KEY) ?? '';
if (initialToken) {
api.setAuthToken(initialToken);
}

const initialNodes = new URLSearchParams(location.search).getAll('nodes');

export function Liveman() {
const [token, setToken] = useState('');
const [token, setToken] = useState(initialToken);
const [needsAuthorizaiton, setNeedsAuthorization] = useNeedAuthorization(api);
const onLoginSuccess = (t: string) => {
setToken(t);
const onLoginSuccess: LoginProps['onSuccess'] = (tokenType, tokenValue) => {
setToken(tokenValue);
setNeedsAuthorization(false);
localStorage.setItem(TOKEN_KEY, `${tokenType} ${tokenValue}`);
};

const [filterNodes, setFilterNodes] = useState<string[] | undefined>();
const [filterNodes, setFilterNodes] = useState<string[]>(initialNodes);
useEffect(() => {
const params = new URLSearchParams(location.search);
setFilterNodes(params.getAll('nodes'));
}, [location.search]);
const getStreams = useCallback(async () => {
const streams = await api.getStreams(filterNodes);
return streams.sort((a, b) => a.createdAt - b.createdAt);
}, [filterNodes]);
}, filterNodes);
const getWhxpUrl = (whxp: 'whep' | 'whip', streamId: string) => {
let url = `/${whxp}/${streamId}`;
if (filterNodes && filterNodes.length > 0) {
if (filterNodes.length > 0) {
const params = new URLSearchParams();
filterNodes?.forEach(v => params.append('nodes', v));
url += `?${params.toString()}`;
Expand All @@ -39,21 +47,18 @@ export function Liveman() {
};

const refStreamTokenDialog = useRef<IStreamTokenDialog>(null);
const renderCreateToken = useCallback((stream: Stream) => {
return (
<Button size="sm" onClick={() => refStreamTokenDialog?.current?.show(stream.id)}>Create token</Button>
);
}, []);

return (
<>
<PageLayout token={token}>
{filterNodes && filterNodes.length > 0 ? null : <NodesTable />}
{filterNodes.length > 0 ? null : <NodesTable />}
<StreamsTable
getStreams={getStreams}
getWhepUrl={streamId => getWhxpUrl('whep', streamId)}
getWhipUrl={streamId => getWhxpUrl('whip', streamId)}
renderExtraActions={renderCreateToken}
renderExtraActions={stream => (
<Button size="sm" onClick={() => refStreamTokenDialog?.current?.show(stream.id)}>Create token</Button>
)}
/>
</PageLayout>
<StreamTokenDialog ref={refStreamTokenDialog} />
Expand Down
4 changes: 1 addition & 3 deletions web/shared/components/streams-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,7 @@ export function StreamsTable(props: StreamTableProps) {
const tokenContext = useContext(TokenContext);

useEffect(() => {
if (tokenContext.token.length > 0) {
streams.updateData();
}
streams.updateData();
}, [tokenContext.token]);

const handleViewClients = (id: string) => {
Expand Down
12 changes: 5 additions & 7 deletions web/shared/hooks/use-refresh-timer.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
import { useCallback, useEffect, useState } from 'preact/hooks';

export function useRefreshTimer<T>(initial: T, fetchData: () => Promise<T>, timeout = 3000, immediate = true) {
export function useRefreshTimer<T>(initial: T, fetchData: () => Promise<T>, timeout = 3000) {
const [data, setData] = useState<T>(initial);
const [isImmediate, _setIsImmediate] = useState(immediate);
const [refreshTimer, setRefreshTimer] = useState(-1);
const isRefreshing = refreshTimer > 0;

const updateData = useCallback(async () => setData(await fetchData()), [fetchData]);
useEffect(() => {
if (isImmediate) {
updateData();
}
}, []);

useEffect(() => {
if (isRefreshing) {
window.clearInterval(refreshTimer);
Expand All @@ -20,6 +16,7 @@ export function useRefreshTimer<T>(initial: T, fetchData: () => Promise<T>, time
window.clearInterval(refreshTimer);
};
}, [updateData, timeout]);

const toggleTimer = () => {
if (isRefreshing) {
clearInterval(refreshTimer);
Expand All @@ -29,6 +26,7 @@ export function useRefreshTimer<T>(initial: T, fetchData: () => Promise<T>, time
setRefreshTimer(window.setInterval(updateData, timeout));
}
};

return {
data,
isRefreshing,
Expand Down

0 comments on commit 368017b

Please sign in to comment.