refactor(front-end): implement a new version of a vnc display using a different rfb type

main
Josue 3 years ago
parent bd04b91e3e
commit 1a64ada0c3
  1. 30
      striker-ui/components/Display/FullSize.tsx
  2. 163
      striker-ui/components/Display/VncDisplay.tsx

@ -1,11 +1,11 @@
import { useState, useRef, useEffect, Dispatch, SetStateAction } from 'react'; import { useState, useRef, useEffect, Dispatch, SetStateAction } from 'react';
import { RFB } from 'novnc-node'; import dynamic from 'next/dynamic';
import { Box, Menu, MenuItem, Typography, Button } from '@material-ui/core'; import { Box, Menu, MenuItem, Typography, Button } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles'; import { makeStyles } from '@material-ui/core/styles';
import CloseIcon from '@material-ui/icons/Close'; import CloseIcon from '@material-ui/icons/Close';
import KeyboardIcon from '@material-ui/icons/Keyboard'; import KeyboardIcon from '@material-ui/icons/Keyboard';
import IconButton from '@material-ui/core/IconButton'; import IconButton from '@material-ui/core/IconButton';
import VncDisplay from './VncDisplay'; import RFB from './noVNC/core/rfb';
import { Panel } from '../Panels'; import { Panel } from '../Panels';
import { BLACK, RED, TEXT } from '../../lib/consts/DEFAULT_THEME'; import { BLACK, RED, TEXT } from '../../lib/consts/DEFAULT_THEME';
import keyCombinations from './keyCombinations'; import keyCombinations from './keyCombinations';
@ -14,10 +14,14 @@ import putFetchWithTimeout from '../../lib/fetchers/putFetchWithTimeout';
import { HeaderText } from '../Text'; import { HeaderText } from '../Text';
import Spinner from '../Spinner'; import Spinner from '../Spinner';
const VncDisplay = dynamic(() => import('./VncDisplay'), { ssr: false });
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
displayBox: { displayBox: {
paddingTop: '1em', paddingTop: '1em',
paddingBottom: 0, paddingBottom: 0,
paddingLeft: 0,
paddingRight: 0,
}, },
spinnerBox: { spinnerBox: {
flexDirection: 'column', flexDirection: 'column',
@ -73,7 +77,7 @@ interface VncConnectionProps {
const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => { const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null); const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const rfb = useRef<typeof RFB>(undefined); const rfb = useRef<RFB>();
const hostname = useRef<string | undefined>(undefined); const hostname = useRef<string | undefined>(undefined);
const [vncConnection, setVncConnection] = useState< const [vncConnection, setVncConnection] = useState<
VncConnectionProps | undefined VncConnectionProps | undefined
@ -82,7 +86,7 @@ const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => {
const [displaySize] = useState<{ const [displaySize] = useState<{
width: string; width: string;
height: string; height: string;
}>({ width: '75%', height: '80%' }); }>({ width: '75vw', height: '75vh' });
const classes = useStyles(); const classes = useStyles();
useEffect(() => { useEffect(() => {
@ -124,9 +128,9 @@ const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => {
if (!scans.length) rfb.current.sendCtrlAltDel(); if (!scans.length) rfb.current.sendCtrlAltDel();
else { else {
// Send pressing keys // Send pressing keys
scans.forEach((scan) => { for (let i = 0; i <= scans.length - 1; i += 1) {
rfb.current.sendKey(scan, 1); rfb.current.sendKey(scans[i], 1);
}); }
// Send releasing keys in reverse order // Send releasing keys in reverse order
for (let i = scans.length - 1; i >= 0; i -= 1) { for (let i = scans.length - 1; i >= 0; i -= 1) {
@ -146,13 +150,21 @@ const FullSize = ({ setMode, uuid, serverName }: PreviewProps): JSX.Element => {
<Box display="flex" className={classes.displayBox}> <Box display="flex" className={classes.displayBox}>
{vncConnection ? ( {vncConnection ? (
<> <>
<Box>
<VncDisplay <VncDisplay
rfb={rfb} rfb={rfb}
url={`${vncConnection.protocol}://${hostname.current}:${vncConnection.forward_port}`} url={`${vncConnection.protocol}://${hostname.current}:${vncConnection.forward_port}`}
style={displaySize} style={displaySize}
viewOnly={false}
focusOnClick={false}
clipViewport={false}
dragViewport={false}
scaleViewport
resizeSession
showDotCursor={false}
background=""
qualityLevel={6}
compressionLevel={2}
/> />
</Box>
<Box> <Box>
<Box className={classes.closeBox}> <Box className={classes.closeBox}>
<IconButton <IconButton

@ -1,122 +1,107 @@
import { useEffect, useRef, memo } from 'react'; import { useEffect, useRef, MutableRefObject, memo } from 'react';
import { RFB } from 'novnc-node'; import RFB from './noVNC/core/rfb';
type VncProps = { type Props = {
rfb: typeof RFB; rfb: MutableRefObject<RFB | undefined>;
// The URL for the VNC connection: protocol, host, port, and path.
url: string; url: string;
style: { width: string; height: string };
// Define width and height via style or separate props viewOnly: boolean;
style?: { width: number | string; height: number | string }; focusOnClick: boolean;
width?: number | string; clipViewport: boolean;
height?: number | string; dragViewport: boolean;
scaleViewport: boolean;
// Force a URL to be communicated with as encrypted. resizeSession: boolean;
encrypt?: boolean; showDotCursor: boolean;
background: string;
// List of WebSocket protocols this connection should support. qualityLevel: number;
wsProtocols?: string[]; compressionLevel: number;
// VNC connection changes.
onUpdateState?: () => void;
onPasswordRequired?: () => void;
// Alert is raised on the VNC connection.
onBell?: () => void;
// The desktop name is entered for the connection.
onDesktopName?: () => void;
connectTimeout?: number;
disconnectTimeout?: number;
// A VNC connection should disconnect other connections before connecting.
shared?: boolean;
trueColor?: boolean;
localCursor?: boolean;
}; };
const VncDisplay = ({ const VncDisplay = (props: Props): JSX.Element => {
const screen = useRef<HTMLDivElement>(null);
const {
rfb, rfb,
style,
url, url,
encrypt,
...opts
}: VncProps): JSX.Element => {
const canvasRef = useRef<HTMLCanvasElement>(null);
/* eslint-disable no-param-reassign */
useEffect(() => {
if (!rfb.current)
rfb.current = new RFB({
...opts,
style, style,
encrypt: encrypt !== null ? encrypt : url.startsWith('wss:'), viewOnly,
target: canvasRef.current, focusOnClick,
}); clipViewport,
dragViewport,
if (!rfb.current) return; scaleViewport,
resizeSession,
showDotCursor,
background,
qualityLevel,
compressionLevel,
} = props;
if (!canvasRef.current) { useEffect(() => {
/* eslint-disable consistent-return */ if (!screen.current) {
return (): void => { return (): void => {
rfb.current.disconnect(); if (rfb.current) {
rfb?.current.disconnect();
rfb.current = undefined; rfb.current = undefined;
}
}; };
} }
rfb.current.connect(url); if (!rfb.current) {
screen.current.innerHTML = '';
rfb.current = new RFB(screen.current, url);
rfb.current.viewOnly = viewOnly;
rfb.current.focusOnClick = focusOnClick;
rfb.current.clipViewport = clipViewport;
rfb.current.dragViewport = dragViewport;
rfb.current.resizeSession = resizeSession;
rfb.current.scaleViewport = scaleViewport;
rfb.current.showDotCursor = showDotCursor;
rfb.current.background = background;
rfb.current.qualityLevel = qualityLevel;
rfb.current.compressionLevel = compressionLevel;
}
/* eslint-disable consistent-return */
if (!rfb.current) return;
return (): void => { return (): void => {
if (rfb.current) {
rfb.current.disconnect(); rfb.current.disconnect();
rfb.current = undefined; rfb.current = undefined;
}
}; };
}, [rfb, encrypt, opts, url, style]); // eslint-disable-next-line react-hooks/exhaustive-deps
}, [rfb]);
const handleMouseEnter = () => { const handleMouseEnter = () => {
if (!rfb.current) return; if (
if (document.activeElement) (document.activeElement as HTMLElement).blur(); document.activeElement &&
rfb.current.get_keyboard().grab(); document.activeElement instanceof HTMLElement
rfb.current.get_mouse().grab(); ) {
document.activeElement.blur();
}
if (rfb?.current) {
rfb.current.focus();
}
}; };
const handleMouseLeave = () => { const handleMouseLeave = () => {
if (!rfb.current) return; if (rfb?.current) {
rfb.current.blur();
rfb.current.get_keyboard().ungrab(); }
rfb.current.get_mouse().ungrab();
}; };
return ( return (
<canvas <div
style={style} style={style}
ref={canvasRef} ref={screen}
onMouseEnter={handleMouseEnter} onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave} onMouseLeave={handleMouseLeave}
/> />
); );
}; };
VncDisplay.defaultProps = { export default memo(VncDisplay);
style: null,
encrypt: null,
wsProtocols: ['binary'],
trueColor: true,
localCursor: true,
connectTimeout: 5,
disconnectTimeout: 5,
width: 1280,
height: 720,
onUpdateState: null,
onPasswordRequired: null,
onBell: null,
onDesktopName: null,
shared: false,
};
const MemoVncDisplay = memo(VncDisplay);
export default MemoVncDisplay;

Loading…
Cancel
Save