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

@ -1,122 +1,107 @@
import { useEffect, useRef, memo } from 'react';
import { RFB } from 'novnc-node';
import { useEffect, useRef, MutableRefObject, memo } from 'react';
import RFB from './noVNC/core/rfb';
type VncProps = {
rfb: typeof RFB;
// The URL for the VNC connection: protocol, host, port, and path.
type Props = {
rfb: MutableRefObject<RFB | undefined>;
url: string;
// Define width and height via style or separate props
style?: { width: number | string; height: number | string };
width?: number | string;
height?: number | string;
// Force a URL to be communicated with as encrypted.
encrypt?: boolean;
// List of WebSocket protocols this connection should support.
wsProtocols?: string[];
// 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;
style: { width: string; height: string };
viewOnly: boolean;
focusOnClick: boolean;
clipViewport: boolean;
dragViewport: boolean;
scaleViewport: boolean;
resizeSession: boolean;
showDotCursor: boolean;
background: string;
qualityLevel: number;
compressionLevel: number;
};
const VncDisplay = ({
const VncDisplay = (props: Props): JSX.Element => {
const screen = useRef<HTMLDivElement>(null);
const {
rfb,
style,
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,
encrypt: encrypt !== null ? encrypt : url.startsWith('wss:'),
target: canvasRef.current,
});
if (!rfb.current) return;
viewOnly,
focusOnClick,
clipViewport,
dragViewport,
scaleViewport,
resizeSession,
showDotCursor,
background,
qualityLevel,
compressionLevel,
} = props;
if (!canvasRef.current) {
/* eslint-disable consistent-return */
useEffect(() => {
if (!screen.current) {
return (): void => {
rfb.current.disconnect();
if (rfb.current) {
rfb?.current.disconnect();
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 => {
if (rfb.current) {
rfb.current.disconnect();
rfb.current = undefined;
}
};
}, [rfb, encrypt, opts, url, style]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [rfb]);
const handleMouseEnter = () => {
if (!rfb.current) return;
if (document.activeElement) (document.activeElement as HTMLElement).blur();
rfb.current.get_keyboard().grab();
rfb.current.get_mouse().grab();
if (
document.activeElement &&
document.activeElement instanceof HTMLElement
) {
document.activeElement.blur();
}
if (rfb?.current) {
rfb.current.focus();
}
};
const handleMouseLeave = () => {
if (!rfb.current) return;
rfb.current.get_keyboard().ungrab();
rfb.current.get_mouse().ungrab();
if (rfb?.current) {
rfb.current.blur();
}
};
return (
<canvas
<div
style={style}
ref={canvasRef}
ref={screen}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
/>
);
};
VncDisplay.defaultProps = {
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;
export default memo(VncDisplay);

Loading…
Cancel
Save