Skip to content

Commit

Permalink
feat: adds IDER component (#975)
Browse files Browse the repository at this point in the history
  • Loading branch information
madhavilosetty-intel authored Jan 4, 2024
1 parent e8a52cd commit 1ed09f0
Show file tree
Hide file tree
Showing 9 changed files with 300 additions and 4 deletions.
54 changes: 54 additions & 0 deletions src/reactjs/IDER/AttachDiskImage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2023
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/

import React from 'react'
import { IDER } from './ider'

export class AttachDiskImage extends React.Component<{
deviceId: string | null
mpsServer: string | null
authToken?: string
}, { selectedFile: File | null, iderState: number }> {

constructor(props) {
super(props)
this.state = {
selectedFile: null,
iderState: 0, // State to track the IDER state
}
}

handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files ? event.target.files[0] : null
this.setState({ selectedFile: file })
}

updateIderState = (newState) => {
this.setState({ iderState: newState })
}

render() {
return (
<div>
<IDER
iderState={this.state.iderState}
updateIderState={this.updateIderState}
deviceId={this.props.deviceId}
mpsServer={this.props.mpsServer}
authToken={this.props.authToken}
cdrom={this.state.selectedFile}
floppy={null}
data-testid="ider-component" iderData={null} />
<input data-testid="file-input" type="file" onChange={this.handleFileChange} />
<button
onClick={() => this.state.iderState === 0 ? this.updateIderState(1) : this.updateIderState(0)}
disabled={!this.state.selectedFile}
>
{this.state.iderState === 0 ? 'Start IDER' : 'Stop IDER'}
</button>
</div>
)
}
}
125 changes: 125 additions & 0 deletions src/reactjs/IDER/ider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2023
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/
import { AMTRedirector, Protocol, AMTIDER, RedirectorConfig } from '@open-amt-cloud-toolkit/ui-toolkit/core'
import React from 'react'

export interface IDERProps {
iderState: number
updateIderState: (newState: number) => void
iderData: IDERData | null
cdrom: File | null
floppy: File | null
mpsServer: string | null
authToken?: string
deviceId: string | null
}

export interface IDERState {
iderState: number
iderData: IDERData | null
}

export interface IDERData {
floppyRead: number
floppyWrite: number
cdromRead: number
cdromWrite: number
}

export class IDER extends React.Component<IDERProps, IDERState> {
redirector: AMTRedirector | null = null
ider: AMTIDER | null = null

constructor(props: IDERProps) {
super(props)
this.state = {
iderState: 0,
iderData: null,
}
}

componentDidMount(): void {
const server: string = this.props.mpsServer != null ? this.props.mpsServer.replace('http', 'ws') : ''
const config: RedirectorConfig = {
mode: 'ider',
protocol: Protocol.IDER,
fr: new FileReader(),
host: this.props.deviceId != null ? this.props.deviceId : '',
port: 16994,
user: '',
pass: '',
tls: 0,
tls1only: 0,
authToken: this.props.authToken != null ? this.props.authToken : '',
server: server
}
this.redirector = new AMTRedirector(config)
}

componentWillUnmount(): void {
this.cleanup()
}

onConnectionStateChange = (redirector, state: number): void => this.setState({ iderState: state })

componentDidUpdate(prevProps) {
// React to changes in props, specifically iderState
if (this.props.iderState !== prevProps.iderState) {
if (this.props.iderState === 1) {
this.startIder()
} else {
this.stopIder()
}
}
}

startIder = (): void => {
this.props.updateIderState(1)
if (this.redirector) {
this.ider = new AMTIDER(this.redirector, this.props.cdrom, null)
this.redirector.onNewState = this.ider.stateChange.bind(this.ider)
this.redirector.onProcessData = this.ider.processData.bind(this.ider)
this.ider.sectorStats = this.iderSectorStats.bind(this)
this.redirector.onStateChanged = this.onConnectionStateChange.bind(this)
this.redirector.start(WebSocket)
}
}

stopIder(): void {
this.props.updateIderState(0)
if (this.redirector) {
this.redirector.stop()
this.cleanup()
}
}

cleanup(): void {
this.redirector = null
this.ider = null
}

iderSectorStats(mode, dev, total, start, len): void {
if (!this.ider) return
if (mode === 1) { // Read operation
if (dev === 0) { // Floppy
this.ider.floppyRead += len * 512;
} else { // CD-ROM
this.ider.cdromRead += len * 2048;
}
} else { // Write operation
if (dev === 0) { // Floppy
this.ider.floppyWrite += len * 512;
} else { // CD-ROM
this.ider.cdromWrite += len * 2048;
}
}
}

render() {
return null
}
}


20 changes: 20 additions & 0 deletions src/reactjs/IDER/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2023
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/

import React from 'react'
import { createRoot } from 'react-dom/client'
import { AttachDiskImage } from './AttachDiskImage'
import i18n from '../../i18n'
// Get browser language
i18n.changeLanguage(navigator.language).catch(() => console.info('error occured'))

const url = new URL(window.location.href)
const params = new URLSearchParams(url.search)

const rootElement = document.getElementById('sol')
if (rootElement != null){
const root = createRoot(rootElement)
root.render(<AttachDiskImage deviceId={params.get('deviceId')} authToken="authToken" mpsServer={params.get('mpsServer')} />)
}
19 changes: 17 additions & 2 deletions src/reactjs/KVM/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,29 @@
import React from 'react'
import { createRoot } from 'react-dom/client'
import { KVM } from './UI'
import { AttachDiskImage } from '../IDER/AttachDiskImage'
import i18n from '../../i18n'
// Get browser language
i18n.changeLanguage(navigator.language).catch(() => console.info('error occurred'))

const url = new URL(window.location.href)
const params = new URLSearchParams(url.search)
const rootElement = document.querySelector('#kvm')
if (rootElement != null){
if (rootElement != null) {
const root = createRoot(rootElement)
root.render(<KVM autoConnect={false} deviceId={params.get('deviceId')} mpsServer={params.get('mpsServer') + '/relay'} authToken="authToken" mouseDebounceTime={200} canvasHeight={'100%'} canvasWidth={'100%'} />)
const auth = ''
root.render(
<React.Fragment>
<AttachDiskImage deviceId={params.get('deviceId')}
mpsServer={params.get('mpsServer') + '/relay'}
authToken={auth}
/>
<KVM autoConnect={false}
deviceId={params.get('deviceId')}
mpsServer={params.get('mpsServer') + '/relay'}
authToken={auth}
mouseDebounceTime={200}
canvasHeight={'100%'} canvasWidth={'100%'} />
</React.Fragment>
)
}
2 changes: 1 addition & 1 deletion src/reactjs/sample/sampleKVM.htm
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
</head>

<body>
<div id="AttachDiskImage"></div>
<div id="kvm"></div>
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js" ></script>
<script src="../../../dist/kvm.min.js" crossorigin></script>

</body>

</html>
29 changes: 29 additions & 0 deletions src/test/attachDiskImage.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2023
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/
import React from 'react'
import { AttachDiskImage } from '../reactjs/IDER/AttachDiskImage'
import { render, fireEvent, screen } from '@testing-library/react'
import { IDER } from '../reactjs/IDER/ider'

describe('AttachDiskImage Component', () => {
test('renders the component', () => {
render(<AttachDiskImage deviceId="123" mpsServer="http://example.com" />)
expect(screen.getByText(/start IDER/i)).toBeInTheDocument()
})

test('handles file selection', () => {
render(<AttachDiskImage deviceId="123" mpsServer="http://example.com" />)
const fileInput = screen.getByTestId('file-input') as HTMLInputElement
const file = new File(['dummy content'], 'example.txt', { type: 'text/plain' })
fireEvent.change(fileInput, { target: { files: [file] } })
expect(fileInput.files).toHaveLength(1)
})

test('handles IDER connect/disconnect', () => {
render(<AttachDiskImage deviceId="123" mpsServer="http://example.com" />)
const button = screen.getByText(/start IDER/i)
fireEvent.click(button)
})
})
45 changes: 45 additions & 0 deletions src/test/ider.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*********************************************************************
* Copyright (c) Intel Corporation 2023
* SPDX-License-Identifier: Apache-2.0
**********************************************************************/
import React from 'react'
import { IDER } from '../reactjs/IDER/ider'
import { AMTRedirector } from '@open-amt-cloud-toolkit/ui-toolkit/core'
import { render } from '@testing-library/react'

// Mocks for external dependencies
jest.mock('@open-amt-cloud-toolkit/ui-toolkit/core', () => ({
AMTRedirector: jest.fn(),
AMTIDER: jest.fn(),
Protocol: { IDER: 'IDER' },
}))
describe('IDER Component', () => {
beforeEach(() => {
// Clear all mocks before each test
jest.clearAllMocks()
})
const props = {
mpsServer: 'http://example.com',
deviceId: 'device123',
authToken: 'token123',
iderState: 0,
updateIderState: jest.fn(),
iderData: null,
cdrom: new File([''], 'cdrom.iso', { type: 'application/octet-stream' }),
floppy: null
}

it('should initialize and clean up redirector', () => {
const { unmount } = render(<IDER {...props} />)
console.log(AMTRedirector)
expect(AMTRedirector).toHaveBeenCalledWith(expect.anything())
unmount()
})
it('renders no visible content', () => {
const { container } = render(<IDER {...props} />)
expect(container).toBeEmptyDOMElement()
})
})



7 changes: 7 additions & 0 deletions webpack.config.externals.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ const reactConfig = {
name: 'ui-toolkit/reactjs/sol',
type: 'umd'
}
},
ider: {
import: './src/reactjs/IDER/AttachDiskImage.tsx',
library: {
name: 'ui-toolkit/reactjs/ider',
type: 'umd'
}
}
},
resolve: {
Expand Down
3 changes: 2 additions & 1 deletion webpack.config.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ module.exports = {
mode: 'production',
entry: {
kvm: './src/reactjs/KVM/index.tsx',
sol: './src/reactjs/SerialOverLAN/index.tsx'
sol: './src/reactjs/SerialOverLAN/index.tsx',
ider: './src/reactjs/IDER/index.tsx',
},
// sourceMap in tsconfig which holds information about your original files when the code is minified
// devtool deal with existing source maps
Expand Down

0 comments on commit 1ed09f0

Please sign in to comment.